#:g1: 暗黙のcond

Posted 2022-02-07 20:04:22 GMT

muLISPの本をながめていたところ、どうも見慣れないカッコの連続が目につくので、詳細を確認したのですが、muLISPではprognなどのボディ部でcondの省略形が使えるようです。
いわば暗黙のcondという感じなのですが、詳細な情報を求めてマニュアルを確認すると、これはマクロや式変換ではなく評価器レベルで実現している機能のようです。

などと文字で書いても判りづらいのでコード例で示しますが、Common Lispで書くと、

(defun fib (n)
  (cond ((< n 1) 0)
        ((< n 2) 1)
        (T (+ (fib n1)
              (fib n2)))))

のようになるものが、muLISPでは

(defun fib (n)
  ((< n 1) 0)
  ((< n 2) 1)
  (+ (fib n1)
     (fib n2)))

のように書けるようです。またprogncondにそのまま置き換わった形式でもないようで、任意の節を述語部の間に挟むことが可能です。

(defun fib (n)
  ((< n 1) 0)
  (print n)
  ((< n 2) 1)
  (print n)
  (+ (fib n1)
     (fib n2)))

暗黙のcondをCommon Lispで真似してみる

そもそも元が評価器レベルで実現しているので、これをマクロで実現するのは手間が掛かる割には上手くいかなさそうです。
今回は妥協してリーダーマクロで実現してみることにしました。

(defun get-block-name (env)
  #+sbcl (caar (sb-c::lexenv-blocks env))
  #+lispworks (caar (compiler::compiler-environment-benv env)))

(defmacro return-innermost (val &environment env) `(return-from ,(get-block-name env) ,val))

(set-syntax-from-char #\] #\))

(set-macro-character #\[ (lambda (srm chr) (declare (ignore chr)) `(if ,(read srm T nil T) (return-innermost ,(cons 'progn (read-delimited-list #\] srm T))))))

ブラケットで囲んだ場合にmuLISPのような挙動となりますが、まあ使い勝手の確認はできそうです。

(defun fib (n)
  "fib"
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (declare (type fixnum n))
  (labels ((fib (n &aux n1 n2)
             [(< n 1) 0]
             [(< n 2) 1]
             (setq n1 (1- n))
             (setq n2 (- n 2))
             (+ (fib n1)
                (fib n2))))
    (fib n)))

(fib 40) → 102334155

まとめ

muLISPの暗黙のcondを再現してみました。
muLISPは1980年代にパソコン用LISPとして結構普及していたようですが、MACLISP系の文法を採用している割には意外な拡張をしていたみたいですね。


HTML generated by 3bmd in LispWorks 8.0.0

comments powered by Disqus