星にゃーんのブログ

ほとんど無害。

RoswellでCommon Lisp環境をセットアップする 2016秋

(2017-3-11更新)RoswellでCommon Lisp環境をセットアップする - ギークもどきの日記帳

Roswellとは (ざっくりと)

Common Lispの処理系やQuicklispのインストール、処理系ごとのオプションの違いの吸収などを行うすごい便利なツール。 Common Lisperなら使って損はない。

インストール

参照Wiki

Home · roswell/roswell Wiki · GitHub

Arch Linux

AURに登録されているので、yaourtでインストールできる。

$ yaourt -S roswell

Homebrew

$ brew install roswell

Windows

Home · roswell/roswell Wiki · GitHub

使っているOSのbitに合わせて、32bitならRoswell-i686.zip、64bitならRoswell-x86_64.zipをダウンロードし解凍、PATHを通す。

ソースからビルド

INSTALL.md参照。

Replの起動

ros runコマンドでREPLが起動する。

$ ros run
* (+ 1 2)

3
* (quit)
$ 

また、roswellはデフォルトでsbcl-1.2.11のバイナリ版を使う。 他の処理系や最新版のsbclを使いたいときは、以下の手順でインストールする。

処理系のインストール (例: Clozure CL)

$ ros install ccl-bin

処理系の切り替え (例: Clozure CL)

$ ros use ccl-bin
$ ros run
Welcome to Clozure Common Lisp Version 1.11-r16635  (DarwinX8664)!

CCL is developed and maintained by Clozure Associates. For more information
about CCL visit http://ccl.clozure.com.  To enquire about Clozure's Common Lisp
consulting services e-mail info@clozure.com or visit http://www.clozure.com.

? 

インストールできる処理系のリストは、ros list versionsで確認できる。

$ ros list version
candidates for ros list versions [impl] are:

abcl-bin
allegro
ccl-bin
clasp
clisp
cmu-bin
ecl
quicklisp
sbcl-bin
sbcl

インストールできるバージョンは、ros list versions [処理系の名前]で確認できる。

$ ros list versions sbcl
Installable versions for sbcl:
Checking version to install....
1.3.15
1.3.14
1.3.13
1.3.12
1.3.11
1.3.10
1.3.9
1.3.8
1.3.7
1.3.6

SLIME

みんなだいすきSLIMEも簡単に使える。 ros emacsで、.emacs.dの設定なしにSLIMEを使えるemacsが起動する。すごい便利。

普通のemacsで使うには以下の手順を踏む。

$ ros install slime

続いて~/.emacs.d/init.elに次の行を追記する。

(load (expand-file-name "~/.roswell/helper.el"))

より詳しい設定方法は、

Home · roswell/roswell Wiki · GitHub

を参照のこと。

Roswell Script

Common LispではRubyPythonと異なり、プログラムをロードしたREPLを用いることが多い。 スクリプト言語のようにバッチ処理を実行するには、処理系ごとに異なった方法を取らねばならず少し不便を感じる。

その点を解決するため、RoswellにはRoswell Scriptという仕組みがある。 ros init <ファイル名>で、Roswellがインストールされている環境上で、単体で実行できるCommon Lispが生成される。

$ ros init fact
Successfully generated: fact.ros

$ cat fact.ros
#!/bin/sh
#|-*- mode:lisp -*-|#
#| <Put a one-line description here>
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  #+quicklisp (ql:quickload '() :silent t))

(defpackage :ros.script.fact.ros.3685511769
  (:use :cl))
(in-package :ros.script.fact.ros.3685511769)

(defun main (&rest argv)
  (declare (ignorable argv)))
;;; vim: set ft=lisp lisp:

このファイルはEmacsVimの両方でCommon Lispソースコードとして認識される。

main関数がエントリーポイントとなる。main関数の引数には、適切にパースされたコマンドライン引数が渡される。 例えば、引数の階乗を返すコマンドは下のようになる。

#!/bin/sh
#|-*- mode:lisp -*-|#
#| Calculating the factorial of given number
exec ros -Q -- $0 "$@"
|#

;;; 今回は使用しないのでコメントアウト
;; (progn ;;init forms
;;   #+quicklisp (ql:quickload '() :silent t))

(defpackage :ros.script.fact.ros.3685511769
  (:use :cl))
(in-package :ros.script.fact.ros.3685511769)

(defun fact (n)
  (if (zerop n)
        1
              (* n (fact (1- n)))))

(defun main (n &rest argv)
  (declare (ignorable argv))
  (format t "~&Factorial ~D = ~D~%" n (fact (parse-integer n)))
  0 ; 実行成功
)

;;; vim: set ft=lisp lisp:

実行例

$ ./fact.ros 3
Factorial 3 = 6

$ ./fact.ros 10
Factorial 10 = 3628800

さらに、Roswellがインストールされていない環境でも(おそらく)動作するexecutableも作れる。 ただし、処理系やライブラリのイメージを含むため、ファイルサイズが50MiBぐらい大きくなる。レッツブルジョア!!

$ time ./fact.ros 10
Factorial 10 = 3628800
./fact.ros 10  0.43s user 0.09s system 98% cpu 0.530 total

$ ros build fact.ros

$ time ./fact 10
Factorial 10 = 3628800
./fact 10  0.00s user 0.01s system 89% cpu 0.018 total

$ du -ah
 54M     ./fact
4.0K     ./fact.ros

割りと速くなった。気がする。もっと計算量の多い処理だと大きく変わるかも。

Elixirで二重数を実装して自動微分するまで

最近プログラミングElixirを読んでいる。

実際にプロジェクトを作る流れを示した練習課題があったり、ライブラリ事情だったり、実用性の高いガイドブックのような形式で、リファレンスじみた退屈さがなくて読みやすい。 Elixir言語だけでなく、周りのエコシステムごと解説されていて、いざ手を動かそうとした時のハードルが非常に低かった。

Elixirでは、自分で型を定義したり、演算子オーバーロードしたりもできる、という内容が本の後半に登場する。といってもざっくりとした紹介があるだけなので少し物足りない。

そこで、練習がてら二重数で自動微分する - Qiitaを参考に、Elixirで二重数を実装してみた。


まずは演算子オーバーロードしたいので、デフォルトの定義をimportしないように設定する。

defmodule DualNumber do
  defstruct a: 0, b: 0

  import Kernel, except: [+: 2, -: 2, *: 2, /: 2]

Inspectプロトコルを実装して、 a + bεの形で表示することにする。

  defimpl Inspect do
    def inspect(%DualNumber{a: a, b: b}, _opts) do
      "#{a}+#{b}ε"
    end
  end

がりがりと算術処理を実装。中置演算子の定義について、引数名は特に宣言がないらしい。 Kernel.+のように書くと、importしなかった関数も呼び出せる。

  def left + right do
    %DualNumber{ a: Kernel.+(left.a, right.a),
                 b: Kernel.+(left.b, right.b) }
  end

  def left - right do
    %DualNumber{ a: Kernel.-(left.a, right.a),
                 b: Kernel.-(left.b, right.b) }
  end

  def left * right do
    %DualNumber{ a: Kernel.*(left.a, right.a),
                 b: Kernel.+(Kernel.*(left.a, right.b), Kernel.*(left.b, right.a)) }
  end

  def conj(d) do
    %DualNumber{ a: d.a, b: (- d.b)}
  end

  def left / right do
    (left * (conj right)) / %DualNumber{a: Kernel.*(right.a, right.a), b: 0}
  end

実際に微分したい関数と、比較用にすでに微分してある関数を定義する。 今回は二重数で自動微分する - Qiitaと同じく { \displaystyle
f(x) = 4 x^2 + 3 x + 2
} を使った。

  def f(x) do
    (%DualNumber{a: 4, b: 0} * x + %DualNumber{a: 3, b: 0}) * x + %DualNumber{a: 2, b: 0} 
  end

  def df(x) do
    %DualNumber{a: 8, b: 0} * x + %DualNumber{a: 3, b: 0}
  end
end

実行するとこうなる。

iex(1)> DualNumber.f(%DualNumber{a: 2.0, b: 0})
24.0+0.# f(2) = 4 * 2^2 + 3 * 2 + 2 = 24
iex(2)> DualNumber.df(%DualNumber{a: 2.0, b: 0})
19.0+0.# df(2) = 8 * 2 + 3 = 19
iex(3)> DualNumber.f(%DualNumber{a: 2.0, b: 1.0})
24.0+19.# f(2+ε) = 24 + 19ε = f(2) + df(2) * ε 

二重数の実部にf(x)が、虚部に微分結果が返っているのがわかる。 複雑な関数の微分をテストしてもおもしろそうだが、今日は時間がないのでここまで。

macOS Sierraで`ros install sbcl`が動かない時の対処法

#52172 (sbcl @1.3.8_0: fix for build under current Xcode 8) – MacPorts

$ export SBCL_MACOSX_VERSION_MIN=10.5
$ ros install sbcl

これでうまくいく。MacportsやHomebrewのsbclも同様。

環境構築2016

homebrew

公式サイトにある通り。 /usr/localのアクセス権限を書き換えないといけなかった記憶があるが、以前インストールしていたからか特に問題なくインストールできた。

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

一応brew doctorは走らせておいた方がいい。

emacs

Mac OS X El Capitanにはemacsがデフォルトでインストールされている。 しかし、バージョンが古いので、Homebrewで新たにインストールする。

$ brew install emacs

あとはgit cloneなりなんなりでGithub上の.emacs.dを引っ張ってくる。

Stack

$ brew install haskell-stack
$ stack setup

roswell

Homebrewでインストール。

$ brew tap roswell/roswell
$ brew install roswell
$ ros setup

あとはWikiを読んでいろいろ設定する。slime周りとか。

tmux

Homebrewでインストール。

$ brew install tmux

Go

$ brew install go

後はよしなにGOPATHを設定する。

ghq

なんかすごいやつ。まだ使っていないので良くわからない。

$ go get github.com/motemen/ghq

Open usp Tukubai

シェル芸のユーティリティ集。

$ghq get https://github.com/usp-engineers-community/Open-usp-Tukubai
$ cd ~/.ghq/github.com/usp-engineers-communitu/Open-usp-Tukubai
$ make install

その他

$ brew install tree
$ brew install reattach-to-user-namespace