マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

現状の LISP on TeX で条件分岐や繰り返しをしてみる

[2012-07-07 補足]「LISP on TeX」の作者は @hak7a3 さんです。念のため。

というわけで、Lisp on TeX なアレ*1で条件分岐と繰り返しを含むコードを書いてみた。

\documentclass{article}
\usepackage{lisp}
\begin{document}
\lispread\expA{% 以下がプログラムコード
((\lambda.(\zero.(((\lambda.(\inc.(((\lambda.(\two.(((\lambda.(\stars.((%
(\lambda.(\leq.(((\lambda.(\isqrt.((\stars.((\isqrt.(((\inc.(\two.())).(%
\two.())).())).())).()))).((\lambda.(\n.(((\lambda.(\iter.(((\iter.(%
\iter.())).(\zero.())).()))).((\lambda.(\self.((\lambda.(\k.(((\lambda.(%
\sk.((((((\leq.((\two.(\sk.())).())).(\n.())).((\lambda.(\z.(((\self.(%
\self.())).(\sk.())).()))).())).((\lambda.(\z.(\k.()))).())).(\zero.()))%
.()))).((\inc.(\k.())).())).()))).()))).())).()))).())).()))).((\lambda.%
(\m.((\lambda.(\n.(((\lambda.(\ra.((((\m.(\ra.())).((\lambda.(\h.((%
\lambda.(\t.((\lambda.(\f.(\t.()))).()))).()))).())).(((\n.(\ra.())).((%
\lambda.(\h.((\lambda.(\t.((\lambda.(\f.(\f.()))).()))).()))).())).())).%
()))).((\lambda.(\f.((\lambda.(\g.((\g.(\f.())).()))).()))).())).()))).(%
)))).())).()))).((\lambda.(\n.(((\n.((\lambda.(\x.((\cons.(*.(\x.()))).(%
)))).())).((\quote.(().())).())).()))).())).()))).((\lambda.(\s.((%
\lambda.(\z.((\s.((\s.(\z.())).())).()))).()))).())).()))).((\lambda.(\n%
.((\lambda.(\s.((\lambda.(\z.((\s.(((\n.(\s.())).(\z.())).())).()))).())%
)).()))).())).()))).((\lambda.(\s.((\lambda.(\z.(\z.()))).()))).()))%
}
\batchmode % 端末出力と \show での停止を抑止
\lispeval\expA\valA % 式 \expA を評価した結果の式を \valA に代入
\errorstopmode % \batchmode を解除
\lispprint\valA % \valA を式の形で出力
\end{document}

上記のコードでは「平方根の整数部」を求める関数 isqrt を実装して、それを 22+1(= 8)に適用した結果の値の個数の「*」(文字列)からなるリストを返す。つまり、結果は「(* *)」であるが、処理系がまだリスト記法に非対応なので、出力は次のようなドット記法となる。((なおまだ開発途中なので、現状ではデバッグ出力が \show で行われていて何回も Enter を押さないと計算が完了しない。今の計算だと膨大な回数になるので、\batchmode に切り替えてデバッグ出力を抑止している。))

実装のロジックは以下のようなものである。

(define zero 0)
(define (inc n) (+ n 1))
(define two 2)
(define (stars n)
  (do ((k 0 (+ k 1)) (x '() (cons "*" x))) ((= k n) x)))
(define leq <=)
(define (isqrt n)
  (let loop ((k zero))
    (let ((sk (inc k)))
      (if (leq (expt sk two) n) (loop sk)
          k))))
(stars (isqrt (expt two (inc two))))

ここで、自然数や真偽値を標準的な方式のラムダ項として表している。(だから two とか leq は実際は単なる定数定義でなく「実装」を持っている。)((Church 記法なので、(expt sk two)(two sk) だし、また stars の定義本体も ((n (lambda (x) (cons "*" x))) '()) で済むことに注意。))

本当は 3³(= 27)とかのもう少し大きな数で試したいのだが、そうすると TeX の main_memory が尽きて落ちるという愉快なことになった。

なお、「現状では LISP というより寧ろ新しい変態言語にしか見えない」という指摘は心の奥に留めておくのがよいであろう。

*1:コミット 672f97fa38df の版。