SwiftによるミニマルなLisp処理系の実装です。コマンドラインで動作するREPL(Read-Eval-Print Loop)を提供します。
- 純粋なSwiftで実装された軽量なLisp処理系
- 対話的なREPLインターフェース
- 基本的なLisp機能をサポート
- 外部依存なし(標準ライブラリのみ使用)
- Swift 5.0以降
- macOS、Linux、またはSwiftが動作する環境
# ファイルに実行権限を付与
chmod +x main.swift# shebang経由で直接実行
./main.swift
# または、swiftコマンドで実行
swift main.swiftプログラムを実行すると、対話型REPLが起動します:
Bitz Lisp Interpreter
Type 'exit' or 'quit' to exit
>
プロンプト > に続けてLisp式を入力すると、評価結果が表示されます。
REPLを終了するには、exit または quit と入力します。
整数および浮動小数点数をサポートします。
> 42
42
> 3.14
3.14
> -10
-10変数名や関数名として使用されます。
> x
Error: Undefined symbol: x
> (define x 10)
10
> x
10括弧で囲まれた要素の並びです。
> (list 1 2 3)
(1 2 3)
> (quote (a b c))
(a b c)t: 真(true)nil: 偽(false)および空リスト
> t
t
> nil
nil
> (if t 1 2)
1
> (if nil 1 2)
2第一級オブジェクトとして扱われます。
> (lambda (x) (* x x))
<function>式を評価せずにそのまま返します。
構文: (quote expr)
> (quote (1 2 3))
(1 2 3)
> (quote x)
x変数を定義します。
構文: (define symbol value)
> (define x 10)
10
> x
10
> (define y (* x 2))
20
> y
20条件分岐を行います。
構文: (if condition then-expr else-expr)
条件が真(nilとfalse以外)の場合はthen-exprを、偽の場合はelse-exprを評価します。
> (if (> 5 3) 100 200)
100
> (if (< 5 3) 100 200)
200
> (if nil "yes" "no")
"no"
> (if 0 "yes" "no")
"yes"無名関数を定義します。
構文: (lambda (param1 param2 ...) body)
> (lambda (x) (* x x))
<function>
> ((lambda (x) (* x x)) 5)
25
> (define square (lambda (x) (* x x)))
<function>
> (square 7)
49
> (define add (lambda (a b) (+ a b)))
<function>
> (add 3 4)
7構文: (+ num1 num2 ...)
複数の数値を加算します。引数がない場合は0を返します。
> (+ 1 2 3)
6
> (+ 10 20)
30
> (+)
0構文: (- num1 num2 ...) または (- num)
複数の数値の減算を行います。引数が1つの場合は符号反転します。
> (- 10 3)
7
> (- 100 30 20)
50
> (- 5)
-5構文: (* num1 num2 ...)
複数の数値を乗算します。引数がない場合は1を返します。
> (* 2 3 4)
24
> (* 5 5)
25
> (*)
1構文: (/ num1 num2 ...) または (/ num)
除算を行います。引数が1つの場合は逆数を返します。
> (/ 10 2)
5
> (/ 100 2 5)
10
> (/ 4)
0.25構文: (= num1 num2)
2つの数値が等しいかを判定します。
> (= 5 5)
t
> (= 3 4)
nil構文: (< num1 num2)
第一引数が第二引数より小さいかを判定します。
> (< 3 5)
t
> (< 5 3)
nil
> (< 5 5)
nil構文: (> num1 num2)
第一引数が第二引数より大きいかを判定します。
> (> 5 3)
t
> (> 3 5)
nil
> (> 5 5)
nil構文: (list elem1 elem2 ...)
引数からリストを作成します。
> (list 1 2 3)
(1 2 3)
> (list)
()
> (list 1 (+ 2 3) 4)
(1 5 4)構文: (car list)
リストの最初の要素を返します。
> (car (list 1 2 3))
1
> (car (quote (a b c)))
a構文: (cdr list)
リストの最初の要素を除いた残りのリストを返します。
> (cdr (list 1 2 3))
(2 3)
> (cdr (quote (a b c)))
(b c)
> (cdr (list 1))
()構文: (cons elem list)
要素をリストの先頭に追加した新しいリストを返します。
> (cons 0 (list 1 2 3))
(0 1 2 3)
> (cons 1 (quote ()))
(1)
> (cons (quote a) (quote (b c)))
(a b c)> (define factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1))))))
<function>
> (factorial 5)
120
> (factorial 10)
3628800> (define fib (lambda (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))
<function>
> (fib 10)
55
> (fib 15)
610> (define length (lambda (lst) (if (= lst (quote ())) 0 (+ 1 (length (cdr lst))))))
<function>
> (length (list 1 2 3 4 5))
5> (define sum (lambda (lst) (if (= lst (quote ())) 0 (+ (car lst) (sum (cdr lst))))))
<function>
> (sum (list 1 2 3 4 5))
15> (define max2 (lambda (a b) (if (> a b) a b)))
<function>
> (max2 10 20)
20
> (max2 30 15)
30> (define map (lambda (f lst) (if (= lst (quote ())) (quote ()) (cons (f (car lst)) (map f (cdr lst))))))
<function>
> (define double (lambda (x) (* x 2)))
<function>
> (map double (list 1 2 3 4 5))
(2 4 6 8 10)処理系は以下のようなエラーを検出して報告します:
> (+ 1 x)
Undefined symbol: x
> (/ 10 0)
Runtime Error: Division by zero
> (car 123)
Runtime Error: car requires a non-empty list
> (lambda x (* x x))
Runtime Error: lambda parameters must be a list
> (1 2 3)
Runtime Error: Cannot apply non-function-
トークナイザー(Tokenizer)
- 入力文字列を字句解析してトークン列に変換
-
パーサー(Parser)
- トークン列を構文解析してS式(LispValue)に変換
-
評価器(Evaluator)
- S式を評価して結果を計算
-
環境(Environment)
- 変数と関数のバインディングを管理
- レキシカルスコープをサポート
入力文字列
↓
トークナイザー
↓
トークン列
↓
パーサー
↓
S式(LispValue)
↓
評価器(環境を使用)
↓
評価結果
この実装は教育目的のミニマルな処理系であり、以下の制限があります:
- マクロシステムなし
- ガベージコレクションの最適化なし
- 末尾呼び出し最適化なし(スタックオーバーフローの可能性)
- 文字列型のサポートなし
- ファイル入出力なし
- エラーメッセージが限定的
この処理系を拡張する場合、以下のような機能追加が考えられます:
- 文字列データ型のサポート
let/let*バインディングcondによる多分岐and/or論理演算beginによる逐次評価set!による変数への再代入- マクロシステム
- ファイルからのコード読み込み
- 末尾呼び出し最適化
- より詳細なエラーメッセージ(行番号など)
このコードはパブリックドメインとして提供されています。自由に使用、改変、配布できます。