Reasoned Schemer (61) run, run*
run
とrun*
(define-syntax run
(syntax-rules ()
((run n (x0 x ...) g ...)
(run n q (fresh (x0 x ...) (== `(,x0 ,x ...) q) g ...)))
((run n q g ...)
(let ((q (var 'q)))
(map (reify q) (run-goal n (conj g ...)))))))
(define-syntax run*
(syntax-rules ()
((run* q g ...) (run #f q g ...))))
fresh
はあとで定義されるのでここではfresh
のまま扱うか
(run n (x0 x ...) g ...)
という形は
q
という変数を導入してq
に(x0 x ...)
を割り当てるようにして
(run n q g ...)
の形に変換する
(run n q g ...)
の形はただの書き替えなんだけど
q
が決め打ちでいいのかなあ
g
の中にq
があったらよろしくなくない?
いや、マクロ展開のときq
は別の変数に置き換えられるのか
いやいや、1行目のq
は決め打ちになるんじゃないか
Macro Stepper使って展開されたものを確認してみよう
まず問題なさげなほうから
(run* (x y) (conj2 (== 'split x) (== 'pea y)))
= (run #f (x y) (conj2 (== 'split x) (== 'pea y)))
= (run #f q (fresh (x y) (== `(,x ,y) q) (conj2 (== 'split x) (== 'pea y))))
q
っていう変数を使ってたら?
(run* (q y) (conj2 (== 'split q) (== 'pea y)))
= (run #f (q y) (conj2 (== 'split q) (== 'pea y)))
= (run #f q (fresh (q y) (== `(,q ,y) q) (conj2 (== 'split q) (== 'pea y))))
なんかあやしくない?
実行すると?
> (run* (x y) (conj2 (== 'split x) (== 'pea y)))
((split pea))
> (run* (q y) (conj2 (== 'split q) (== 'pea y)))
((split pea))
うーん
普通に結果が出てる
いいのかなあ
もう1回展開
(let ((q (var 'q)))
(map
(reify q)
(run-goal
#f
(conj (fresh (q y) (== `(,q ,y) q) (conj2 (== 'split q) (== 'pea y)))))))
var
で導入される変数とfresh
で導入される変数は別ってことかな
考えてみると別物だけど
上の式でどのq
が何なのかというとまだ理解が足りない