Reasoned Schemer (75) fresh、run*
こういう式を短く書く話
(run* r (fresh (x) (fresh (y) (conj2 (== 'split x) (conj2 (== 'pea y) (== `(,x ,y) r))))))
(fresh (x) (fresh (y) g ...)
は(fresh (x y) g ...)
と書ける
(run* r (fresh (x y) (conj2 (== 'split x) (conj2 (== 'pea y) (== `(,x ,y) r)))))
これはfresh
マクロの力
このへんがやってくれる
((fresh (x0 x ...) g ...)
(call/fresh 'x0
(lambda (x0)
(fresh (x ...) g ...))))
結果を作るために使っていたr
を使わないように書くこともできる
(run* (x y) (conj2 (== 'split x) (== 'pea y)))
これはrun
マクロがやってくれる
((run n (x0 x ...) g ...)
(run n q (fresh (x0 x ...) (== `(,x0 ,x ...) q) g ...)))
run*
やfresh
はconj2
を含む
(run* r (fresh (x y) (== 'split x) (== 'pea y) (== `(,x ,y) r)))
(run* (x y) (== 'split x) (== 'pea y))
これは
((fresh () g ...) (conj g ...))
とか
((run n q g ...)
(let ((q (var 'q)))
(map (reify q) (run-goal n (conj g ...)))))))
とかが面倒を見ている
あとconj
マクロ
(define-syntax conj
(syntax-rules ()
((conj) succeed)
((conj g) g)
((conj g0 g ...) (conj2 g0 (conj g ...)))))