reasonedschemer
defrelもわかったことにするとだいたいわかった感じになるかなあ > (run 5 x (lolo `((a b) (c d) . ,x))) '(() (()) ((_0)) (() ()) ((_0 _1))) こういうのもまじめに追いかければなぜこの順になるかわかるはずだけどそこまで元気は出ない defrelのlambda (…
ところで(run 1 x (listo ``(a b c . ,x)))はdefrelにlambda ()がないと帰ってこない やっとlambda ()の存在意義を確認
3. Seeing Old Friends in New Ways Translationの続きだけどTranslationよりも再帰が出てきたことに注目して (defrel (listo l) (conde ((nullo l)) ((fresh (d) (cdro l d) (listo d))))) > (run* x (listo `(a b ,x d))) '(_0) 1周目はTranslationすると…
さらっといく nulloとpairo
リストの操作 まずはcaro > (defrel (caro p a) (fresh (d) (== (cons a d) p))) > (run* q (caro '(a c o r n) q)) '(a) なんでconsが理解できるんだろうと思ってたけどunifyとかがリストを前提とした作りになってるからだな ていうかむしろリストしか知ら…
> (run* (x y) (teacupo x) (teacupo y)) '((tea tea) (tea cup) (cup tea) (cup cup)) こうやって組み合わせで増えていくのがrelationalっぽいような気がする
defrel登場 > (defrel (teacupo t) (disj2 (== 'tea t) (== 'cup t))) > (run* x (teacupo x)) '(tea cup)
こういう式を短く書く話 (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) (== `(…
disj2のほうがconj2よりもイメージしやすい気がする ちょっと加速しよう ((disj2 fail fail) empty-s)は追ってもあっさりしすぎててわからなさそうだから このへんで
> (run* q (conj2 (== 'corn q) (== 'meal q))) '() これはどういう動きか ((conj2 (== 'corn q) (== 'meal q)) empty-s) = (append-map-inf (== 'meal q) ((== 'corn q) empty-s)) = (append-map-inf (== 'meal q) '(((#(q) . corn)))) = (append-inf ((== …
fuseされていなければ変数がdifferent 変数の名前が違うだけなら式の値は変わらない xがyの中に現れることをoccurという このあたりはOK conj2登場
すこしだけ複雑なやつ > (run* q (fresh (x) (== `(((,q)) ,x) `(((,x)) pod)))) '(pod) とはいっても==を評価したstreamの要素がふたつになったくらい
> (run* q (fresh (x) (== x q))) '(_0) xとqがfuseしている というのは`(,x . ,q)というassociationがあるということ でもxもqもfreshなので_0
いろいろ考え直さないとか? ↓みたいなのやっていくときはqをqのままにしないで書き替えてったほうがいいのかなー (run* q (== q 'pea)) = (run #f q (== q 'pea)) = (let ((q (var 'q))) (map (reify q) (run-goal #f (conj (== q 'pea))))) = ...
まだ理解したっていう手ごたえを感じてないんだけどどうするっていうアイデアもないので進める > (run* q succeed) '(_0) qはfresh 10章までsucceedって何かあんまり意識してなかったりもした
ひとつひとつの関数のお仕事をひとことで言えて やってみよう その前に用語のまとめ
さて読み返してみるとは言ったもののどうやっていくか せっかく実行できるようになったんだから式を実行してみるのはもちろんだけど デバッガーで追いかけたりしてみるかな DrRacketのデバッガー、いまひとつどう動いてるかよくわからなかったりする とりあ…
ForewordとかPrefaceから読み返してみる そうだそういうことやってたんだ、という気分(忘れてる relationとgoalを理解して使えるようになる(第1章〜第8章) relationalでない演算子を使い、pureでないrelational programmingを行う(第9章) Schemeで関係型プ…
お次はこれ (let ((s-inf ((disj2 (nevero) (== 'olive x)) empty-s))) s-inf) = ((disj2 (nevero) (== 'olive x)) empty-s) = ((lambda (s) ((nevero) s) (append-inf ((== 'olive x) s))) empty-s) = (append-inf ((nevero) empty-s) ((== 'olive x) empty…
次からappend-infが登場 うまく追っかけられるだろうか (let ((s-inf ((disj2 (== 'olive x) (nevero)) empty-s))) s-inf) = ((disj2 (== 'olive x) (nevero)) empty-s) = ((lambda (s) (append-inf ((== 'olive x) s) ((nevero) s))) empty-s) = (append-in…
まだイメージしきれないのは(append-inf s-inf t-if)で (lambda () (append-inf t-inf (s-inf)))するところかな たぶん↓とかもそういうところなんだよな (run 12 l (proper-membero'tofu l))の値の順番がなぜこうなるのか謎 append-infの続きあたりからもう…
ということで2周目に入るよ! いきなり始めに戻らずに10章を読み直している
conda (define-syntax conda (syntax-rules () ((conda (g0 g ...)) (conj g0 g ...)) ((conda (g0 g ...) ln ...) (ifte g0 (conj g ...) (conda ln ...))))) condeと違ってifteの入れ子にしないといけないから再帰な形になるってことか やってみる
fresh (define-syntax fresh (syntax-rules () ((fresh () g ...) (conj g ...)) ((fresh (x0 x ...) g ...) (call/fresh 'x0 (lambda (x0) (fresh (x ...) g ...)))))) やってみる
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…
Connecting the Wires いちいち(let ... (map ... (call/fresh ... (disj2 ... (disj2 ...)))))などとは 書いていられないのでマクロ書くよ!という章 まずdisj2のいくつでもゴールを取れる版disj実際にはcondeが使われるので補助的な位置
こんどはonce これはconduのもとになってるはず
if-then-elseとconda、なんとなくつながりがありそうな気はするんだけど どうなるんだ? condaの式をifteで書けるはずなんだよな (conda (#s #u) (#s #s))を書き直してみよう
興奮するのもいいけど、なにか忘れてませんか? condaとconduはどうしたっけ そうですね ifteってのを定義します IF-Then-Elseの略
Let’s put the pieces together! piecesをtogetherすると完成? appendoをこの章で定義した関数だけで書く