男は男らしく
(単なる余興で冗談です)
Maximaを通じてLISPの柔軟性を感じることができました。となると私にとって、LISPの欠点は、ただ2点。
- 関数型なのに関数に見えなくてリストに見える。しかも(で始まって、女々しい。
- UNIXのコマンドと同じくらい、関数名に省略形が多い。
結局、この2点が最初の大きな障壁となって、LISPプログラマ人口を増えなくしているように思えます。2点目の課題は時間をかけて解決するしないですが、1点目はプリプロセッサで解決可能と思って、なぜかMaximaで作りました。題して、「男は男らしく、関数は関数らしく」
preprocessor(file) := block( [rs, ws, line, c, prefetch], rs : openr(file), ws : openw(concat(file, ".lisp")), do ( line : readline(rs), prefetch : "", if line = false then return(), for c in charlist(line) do ( if (constituent(c) = false) or (c = "'") then ( printf(ws, concat(prefetch, c)), prefetch : "") elseif c = "(" then if slength(prefetch) = 0 then printf(ws, c) else ( printf(ws, concat(c, prefetch, " ")), prefetch : "") else prefetch : concat(prefetch, c)), printf(ws, concat(prefetch, "~%"))), close(ws), close(rs) )$
このプリプロセッサを通すと、とっても関数らしい以下のコードが、疑似LISPのコードになります。
defun(Fibonacci (n) cond( (or(equal(n 1) equal(n 2)) 1) (true plus(Fibonacci(minus(n 1)) Fibonacci(minus(n 2))))))
↓
(defun Fibonacci (n) (cond ((or (equal n 1) (equal n 2)) 1) (true (plus (Fibonacci (minus n 1)) (Fibonacci (minus n 2))))))
余興以上にするにはパースツリーを実装して二項演算子にまで踏み込まないといけないが、このページは「それを書くには狭すぎる。」
本当はこう書きたい。
define(Fibonacci (n) condition( (((n=1) or (n=2)) 1) (true (Fibonacci(n-1)+Fibonacci(n-2)))))
上のプリプロセッサは単なるフォーマッタで、何ら意味を変えていないので、フォーマット前の表現もLISPだと言えますが、二項演算子を導入すると、演算子を評価する直前に関数化する必要があって、アトムやリストの意味が変わってしまいます。ここでLISPじゃなくなるんでしょうね。MaximaもLISPの拡張ではなくて、LISPで実装した別言語だと頷けます。