この記事はLispアドベントカレンダー2021の24日目の記事です。
TL; DR
自作Lispすすみました。
はじめに
自作Lispをつくっています、という話はアドベントカレンダー2日目の記事に書きました。今日は24日。あれからどのような進捗がでたのかを書きます。
2日目の状態と24日目時点の状態
本記事を書いている時点での最新コミットはこちらです。比較のためcompareを出してみました。
61コミッツ! 意外とがんばっていますね。何が増えたのかはTODO.mdのdiffを見るとよいでしょう。
- [x] integers
- [ ] floating point numbers
- - [ ] dot pairs
- - [ ] garbage collection
- - [ ] proper lists
- - [ ] arrays
- - [ ] hash tables
+ - [x] dot pairs
+ - [x] garbage collection
+ - [x] `()`
+ - [x] proper lists
+ - [x] arrays
+ - [x] hash tables
- [ ] symbols
- [ ] keywords
ふむふむ。ドット対とリストと配列とハッシュテーブルが登場したと。GCはつくってると2日目記事でも言ってましたが、無事完成しました。ただテストあまり書いてないのですよね。いまはGCのルートオブジェクトは標準入出力だけしかないのであまりGCの領域を深くコピーする (※コピーGCです) 状況が発生せず大抵ぜんぶ片付けられてしまうので、束縛 (やコールスタック) が誕生したあたりで不可解な現象を楽死めそうです。
あとはハッシュテーブル。#{1 100 1 200}
が#{1 200}
になってほしい問題はおもしろかったです。キーの比較をeq
ではなくeql
でやらないと整数 (internとかないのでオブジェクト同値にはならない) がハッシュ値同じにならないな、と思ってeql
を追加しました。が、そもそも問題はハッシュ関数の問題でした。脳死でuintptr_t
を剰余するハッシュ関数で最初実装していたのでeql
の前のところでポインタ同値を見ていて意味がなかったという。なので最終的にはもうちょっとobject-awareなハッシュ関数を実装して (このコミット)対処しました。~~まあタグ値足して剰余の脳死実装なのは変わりませんが。~~
read
とprint
にはテスト書いてないので、細かいところの挙動は不安です。そういえばハッシュテーブルもテストまだしてない。テストしたい。めんどい。つらい。
read
といえば、2日目にはこんなことも言っていました:
あとはひたすら実装していくだけなのですが、継続の実現だったり、途中で止められるパーサだったり、大きなものもつくらねばならないのでじっくり楽しめそうです。GCもありますしね。
途中で止められるパーサにしたかったですが、ちょっと今の肥大化したリーダをそうするのはむずかしそうだなーどうしようかなー、という感じです。そういえば存在をスキップされた浮動小数点数とかもあります。2日目時点けっこう疲れていて複雑化しそうな整数・浮動小数点数のリーダと向き合えますか、という意味では向き合えなかったので放置しています。モチベを維持することを優先した結果です。
今後のこと at 24日目
直近次につくるのはシンボルですね。シンボルなのでintern
機構やグローバル束縛の概念が必要になるので骨太そうです。ユーザが触れるパッケージは実装しないつもりなので、シンボルとキーワードは単純に固定の2パッケージに入るようなのを考えてます。
シンボルが終わると組み込みの型の実装フェーズは終了するので、次は特殊形式を充実させていきます。cond
とかlet
とかlambda
とか。たのしそうですね。わくわくしてきました。
tanaka-lispはアドベントカレンダーの記事のためというのもあって12月はもりもり触っていましたが、今後はちまちま進めていくことにしました。c-lessonの第三回に改めて取り組みたいですし、勢いでD言語を触りはじめたし、あと年末年始はゲームボーイエミュレータつくりにちょっと挑戦したい。
余談
ベアメタル de Lispしたくなってしまった今日このごろです。
n月刊ラムダノートの川合史郎さんのLISP 1.5記事を読み返していたんですが、純Lispの基本関数・特殊形式って自己記述のための機械語といって差し支えないなと思ったのですよ。これらを機械語に落し込めばベアメタルでLispできそう(それはそう
なので機械語Lisp挑戦したい。したい。