#:g1: レトロLisp探検: Conniver

Posted 2016-12-23 21:57:44 GMT

方言の系統

Conniver

主要開発者

Drew V. McDermott、Gerald J. Sussman

登場時期

1972年

特徴

Plannerから続くAI向け言語。Lispをベースにデータベースとユーザーが操作可能な制御フローを持つ

後続への影響

Lisp Machine Lisp

概要

Conniverは、Plannerに影響を受けつつ、BobrowとWegbreitの制御機構(多分スパゲティスタック)や、Muddle(MDL)のオプショナル引数等を取り込み、さらにデータベースと、ジェネレータ等を持つLisp系言語です。

基本的にLispだそうですが、データを登録していく仕組みが組込まれていて、addや、removeで追加/削除できます。
それらのデータを元に、Possibilities Listを作成しデータを問合せたり制御を移したりしますが、そこにジェネレータが使われます。

関数の定義は、MACLISP系のdefunと似た感じのcdefunで、ジェネレータは、cdefgenで定義します。

MDLから影響を受けた、ラムダリストがあり、“OPTIONAL”、“REST”、“AUX”が使えます。なお“AUX”は、ラムダリスト内ではなくボディで利用。
MDLでは、“REST”ではなく、“TUPLE”でしたが、Common Lispの&restの祖先はConniverということになりそうです。

(cdefun foo ("optional" foo "rest" args)
  "aux" (x y z)
  ...)

は、Common Lispで書くと

(defun foo (&optional foo &rest args &aux x y z)
  ...)

になります。
letのネストが減るので、cdefunの“aux”は割合に良いかもしれないですね。

ボディ部は暗黙のprogになっていることが多くcdefunを始め、condの節まで暗黙のprogでタグを記述することができ、goで飛ぶことが可能です。

下記は、マニュアルにあるアイテムのデータベースへの登録/削除とジェネレータ呼び出しを含む例ですが、手続き型の制御機構を強化した印象が強いです。

(cdefun forcewin (player square)
  "aux" ((context (push-context context)))
  (add '(has ,player ,square))
  (remove '(free ,square))
  (makemove (other player))
  (return (try-next (winmoves player) nil)))

(cdefgen winmoves (player) "aux" (square1 p1 square2 p2 x) (csetq p1 (fetch '(has ,player ?square1))) :outerloop (try-next p1 '(adieu)) (csetq p2 (fetch '(has ,player ?square2))) :innerloop (try-next p2 '(go 'outerloop)) (cond ((lessp square1 square2) (cond ((csetq x (third-in-row square1 square2)) (cond ((present '(free ,x)) (note x))))))) (go 'innerloop))

Conniverで良く知られている機構に、Hairy Control Structureというものがありますが、Scheme方面では継続の操作として整理された所です。

呼び出した関数から途中で一度抜けて、残りを実行したりしていますが、

(cdefun printfoobar () "aux" (place)
  (cond ((csetq place (zowie))
         (go place))))

(cdefun zowie () (print 'foo) (return (tag 'printbar)) :printbar (print 'bar) nil)

(printfoobar) ;>> foo bar ;=> nil

Schemeだとこんな感じでしょうか(Scheme力が弱くていまいち)

(define (printfoobar)
  (define place (zowie))
  (place)
  (values))

(define (zowie) (call/cc (lambda (return) (print 'foo) (call/cc (lambda (printbar) (return printbar))) (print 'bar) (lambda () #f))))

(pirntfoobar) ;>> foo ;>> bar

ConniverからベースのLisp処理系の関数は任意に呼び出せますが、LispからConniverの関数を呼ぶには、@構文等を使いる等作法があるようです。
Micro-Plannerでもそんな感じでしたが、今でいうとShenが似たような感じかなあと思います(LispからShenを呼ぶ方法は用意されていないですが)

後続のLispに影響を与えていそうなところ

closure構文がありますが、これはLisp Machine Lispのclosure構文と似た感じです。しかし、取り込む変数の指定がないので、環境全部を取り込むのかもしれません。

また、関数と変数の文脈の曖昧さ/意図せぬシャドウを無くすためにcallがありますが、MACLISPのfuncallはこれに影響を受けて導入されたのかもしれません。
もしそうならMACLISPにもcallという名前そのままで導入して欲しかったかも。

体験

Sail Dartにソースらしきものがありますが新しめのMACLISPでは動きませんでした。

是非、誰か動かしてみて下さい……。

まとめ

今回は、Conniverを紹介してみました。
Planner→Conniver→Scheme→Racketと続く命名シリーズですが、Conniverはちょっと影が薄いかもしれないですね。
ただ、多様な制御機構については、Schemeに受け継がれていった気はします。

参考文献


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus