見出し画像

AIと一緒に新しい言語処理系を作ってみた

Claude-3 Sonnetがだいぶ良いので、前々から考えていた、「Lispっぽい記法で書けるけど他の言語に慣れた人にも使える言語」の処理系を作ってみた。仮にEasyLispという名前にした。

この言語ではこんな感じでプログラムが書ける

(define person (object))
(set! person.name "Alice")
(set! person.age 30)
(print person.name)

personというオブジェクトのプロパティをnameやageがあって、これをドット記法で指定するとpersonオブジェクトのプロパティにアクセスできる。

同じことをCommon-Lispでやろうとするとこうなる

(defun example ()
  (let ((person (make-object :name "Alice" :age 30)))
    (format t "Name: ~A~%" (get-prop person 'name))
    (format t "Age: ~A~%" (get-prop person 'age))

見てわかるように、LispのCLOS(Common Lisp Object System)で書くとかなり冗長になる。

これがLispがシンプルで強力であるにも関わらずイマイチ流行らない原因なのではないかと思う。

Lispには長い長い歴史があって、その歴史の中でいろいろな方言が生まれ、しかしCommonLispとして統一された後、その後生まれたオブジェクト指向の要素をCommonLisp上に実装するときにCLOSが生まれた。

ただ、シングルクォートをアポストロフィとして使うとか、ちょっと他の言語ユーザーにはあまり馴染みのない書き方をしなければならなくて不便なのでこのあたりがもっとJavaScriptとかCっぽく書ければいいなと思っていたのだ。

ついでに、最近見たLispの入門書(というかWebページ)で、動作中のWebサーバーにオンザフライで関数を書き換えるという話があって「それはLispらしいし面白い」と思ったので、それも実装することにした。

REPLを起動すると同時にHTTPサーバも起動し、ダイナミックルーティングができる。

(define (greet name) (list "Hello" name))
(define-route "greet" greet)

こうすると、http://localhost:8000/greet?name=Bobを呼び出すと["Hello", "Bob"]が返ってくる。

今の所これだけだが、僕が感動したのは、ここまでの一連のコードが、Claude-3だけでできたこと。最終的に細かいバグは僕が修正したのだが、Claude-3に「お前使いすぎだから夜11まで使用禁止な」と怒られるくらい使った。

簡単なものならエラーなしで作れるが、高度になってくるとバグが増える。このバグをGemini 1.5 Proに直させようとしたらGemini 1.5 Proは「これは正当なLispではありません。正当なLispはこう書きます」とクソみたいなことを言ってくる。全く、作った連中の性格がわかるというもの。

正当なLispが嫌だからこれを作ってんだろうが。
ChatGPTに聞くと結構いい感じのことを言ってくれる。さすが大丈夫マイフレンド。

ドット記法周りは最初はChatGPTとかに書かせていたんだけど最終的に細かいバグがあって動かなくて自分で修正した。これでもまだネスティングとかはサポートしてない。

ただ、子供の頃から遊びで言語処理系を作ったことは何度かあるが、こんなに簡単に言語処理系ができてしまうこと自体に感動した。AIを使いこなすにはやはりプログラミングを理解していないといけない。そうすれば自分で新しい言語を作ることだってできるのだ。

まだ全然機能が足りないが、作った処理系を記念に置いておく