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向けバイナリを使う方法
  • どうインストールするか (どうパッケージ管理するか)
    • Roswellを使う (Roswell内でquicklispをセットアップさせる。) [ダウンロードページ] からインストーラをダウンロードする。

インストール

  1. Windows用のRoswellインストーラをダウンロード

  2. 圧縮ファイルを展開してパスを通す

  3. 初期セットアップ
    自動でWindows向け sbcl-bin/2.3.0 がインストールされる。

     > ros setup  
    

    特定のバージョンのSBCLをインストールする場合は以下 (roswellトップページ のコマンドクリックリファレンス参照)

     > ros install sbcl-bin  
    

    バージョン確認

     > 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
    

実行

  1. REPLの実行 REPLに入る(&Hello World)

     > ros run
     * (format t "Hello World")
     Hello World
     NIL
     *
    

    REPLを抜ける

     * (exit)
    

    ※ エラー時のデバッガを抜けるときには、abort で抜ける。

  2. Listスクリプトの実行(エディタ等で別途作成したListスクリプトの実行)
    実装を指定して、lispファイルを直接実行することも可能。(Roswell標準は、.rosスクリプトテンプレートによる実行)

     (defun main ()
         (write-line "Hello world!")
     )
    
     > ros test.lisp
     Hello world!
    
  3. 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バイナリでやる意味があるのかというと、わからない。

参考