2023年に Windows で Lisp を始める (SBCL)
前提
- どの方言を選ぶか?
- Common Lisp, Clojure, Scheme, Emacs Lisp …
- 実質的な標準であるCommon LispとJavaのリソースが使えるClojureとで考え、Common Lispを選択
- どの実装を選ぶか?
- GNU CLISPは2010年7月に更新が止まっている
- SBCL (Steel Bank Common Lisp) を選択した
- どの方式でインストールするか? (Windows上に作ることが前提)
- Linux向け処理系を模倣した環境をWindows上で作り、Liunx向けバイナリを使う方法
- WSL (Windows subsystem for Linux) , MinGW, Cygwin 等
- Windows向けバイナリを使う方法
- Linux向け処理系を模倣した環境をWindows上で作り、Liunx向けバイナリを使う方法
- どうインストールするか (どうパッケージ管理するか)
- Roswellを使う (Roswell内でquicklispをセットアップさせる。) [ダウンロードページ] からインストーラをダウンロードする。
インストール
Windows用のRoswellインストーラをダウンロード
圧縮ファイルを展開してパスを通す
初期セットアップ
自動でWindows向け sbcl-bin/2.3.0 がインストールされる。> ros setup
特定のバージョンのSBCLをインストールする場合は以下 (roswellトップページ のコマンドクリックリファレンス参照)
> ros install sbcl-bin
ros install sbcl
(最新版SBCLのインストール)を実行しようとすると、内部的にMinGWとMSYS2+がインストールを試み、内部的なMSYS2+のインストールに失敗する不具合が数年残っているので注意
バージョン確認
> ros list installed Installed implementations: Installed versions of sbcl-bin: sbcl-bin/2.3.0
特定のバージョンをデフォルトに変更
> ros use sbcl-bin/1.2.3
現在のデフォルト実行バージョンを確認 (ハイフン2個 + スペース + ハイフン2個であることに注意)
> ros run -- --version SBCL 2.3.0
実行
REPLの実行 REPLに入る(&Hello World)
> ros run * (format t "Hello World") Hello World NIL *
REPLを抜ける
* (exit)
※ エラー時のデバッガを抜けるときには、
abort
で抜ける。Listスクリプトの実行(エディタ等で別途作成したListスクリプトの実行)
実装を指定して、lispファイルを直接実行することも可能。(Roswell標準は、.rosスクリプトテンプレートによる実行)(defun main () (write-line "Hello world!") )
> ros test.lisp Hello world!
Roswell スクリプトの作成
可搬性の高いスクリプト生成の為、.rosスクリプトが生成できる>ros init test Successfully generated: test.ros
#!/bin/sh #|-*- mode:lisp -*-|# #| exec ros -Q -- $0 "$@" |# (progn ;;init forms (ros:ensure-asdf) #+quicklisp(ql:quickload '() :silent t) ) (defpackage :ros.script.test.3882226987 (:use :cl)) (in-package :ros.script.test.3882226987) (defun main (n &rest argv) (declare (ignorable argv)) ; 自動生成されたテンプレートのうち、以下独自のLispスクリプトの挿入 (format t "~&Multiplied ~D = ~D~%" n (* (parse-integer n) 2)) ) ;;; vim: set ft=lisp lisp:
実行する
> ros test.ros Multiplied 3 = 6
※引数を2倍するだけのコード
単体実行ファイルの生成
> ros build test.ros
実行ディレクトリに test.exe
が生成される。
> test.exe 3 Multiplied 3 = 6
なお実行ファイルのサイズは44MBを超えました(真顔)
実例
実行フォルダ内のファイル一覧を取得し、コマンドライン引数の文字列を含むファイルのみ一覧表示するプログラムの例。
SBCL Lispスクリプトの場合
(defun main (args) (write-line (uiop:strcat "Searching '" args "' in current directory")) (dolist (x (uiop:directory-files "./")) (if (search args (file-namestring x)) (print (file-namestring x)) ) ) )
> ros folder-search.lisp sear Searching 'sear' in current directory "folder-search.lisp" "folder-search.ros"
Roswellスクリプトの場合
#!/bin/sh #|-*- mode:lisp -*-|# #| exec ros -Q -- $0 "$@" |# (progn ;;init forms (ros:ensure-asdf) #+quicklisp(ql:quickload '() :silent t) ) (defpackage :ros.script.folder-search.3882230062 (:use :cl)) (in-package :ros.script.folder-search.3882230062) (defun main (s &rest argv) (declare (ignorable argv)) (write-line (uiop:strcat "Searching '" s "' in current directory")) (dolist (x (uiop:directory-files "./")) (if (search s (file-namestring x)) (print (file-namestring x)) ) ) ) ;;; vim: set ft=lisp lisp:
> ros folder-search.ros ear Searching 'ear' in current directory "folder-search.lisp" "folder-search.ros"
補足
Windows 環境の Roswell のListスクリプト内で ql:quickload
を使おうとすると、gccが見つからない旨のエラーが出る。(Windowsなのでそりゃそうだが)
MinGW等でgcc 入れておくことで解決するかもしれないが、茨の道になろうことは想像に難くない。
そこまでして(WSL等仮想環境でなく)Windowsバイナリでやる意味があるのかというと、わからない。
参考
- とほほのLISP入門
- Roswell で環境構築して Common Lisp を書いてみる - Neo's World
- いまから始めるCommon Lisp - Qiita
- [Day 3: Roswell: Common Lisp scripting - fukamachi tech notes] (https://fukamachi.hashnode.dev/day-3-roswell-common-lisp-scripting)
- [Common Lisp Programming - M.Hiroi's Home Page] (http://www.nct9.ne.jp/m_hiroi/clisp/index.html)
- [The Common Lisp Cookbook] (https://lispcookbook.github.io/cl-cookbook/)
- LISP - Wikibooks