Reasoned Schemer (85) alwayso
6. The Fun Never Ends …
この章(も)、1周目は消化不良気味だったけど今回はどうだろう
(defrel (alwayso) (conde (succeed) ((alwayso))))
とりあえず一回succeedしてさらにもう一度
ということはすんなりわかるようになった
あとはsuspensionのおかげで単なる無限ループではなくて一回戻ってきては次に進んでくれることもわかった
> ((alwayso) `((,q . onion)))
#<procedure:...r/minikanren.rkt:147:9>
> (((alwayso) `((,q . onion))))
'(((#(q) . onion))
.
#<procedure:...r/minikanren.rkt:147:9>)
何回forceすればいいのかっていうのはいまだにわからない
ひとつずつカッコを増やして試している
take-inf
なら必要なだけforceしてくれる
> (take-inf 3 ((alwayso) empty-s))
'(() () ())
雰囲気的に書けば((alwayso) empty-s)
は(() () () ...
て感じなんだな
> (run 5 q (== 'onion q) (alwayso))
'(onion onion onion onion onion)
こういうのもわかる
((conj2 (== 'onion q) (alwayso)) empty-s)
= (append-map-inf (alwayso) ((== 'onion q) empty-s))
= (append-map-inf (alwayso) `(((,q . onion))))
= `(((,q . onion)) ((,q . onion)) ((,q . onion)) ...)
alwayso
が``((,q . onion))
を受け取って無限に成功し続けるので
``((,q . onion))
が無限に返される
反対にしても同じだよな?
> (run 5 q (alwayso) (== 'onion q))
'(onion onion onion onion onion)
OK
こっちはalwayso
が無限に()
を渡してくるので(== 'onion q)
がそのたびに
((,q . onion))
を返してくる感じ
(run 1 q (== 'garlic q) (alwayso) (== 'onion q))
が返ってこないのもわかる
まずq
と'garlic
がunifyして、alwayso
がいったん成功して
でq
と'onion
をunifyしようとして失敗する
alwayso
のconde
節がもうひとつあったことを思い出してもう1回試してみると
また成功して・・・
ちょっとテキトーすぎるかな
上のと同じレベルで書くと
alwayso
が``((,q . garlic))
を受け取って無限に成功し続けて
``((,q . garlic))
を無限に(== 'onion q)
に渡し続けて返ってこない
てことだな
> (run 1 q
(conde ((== 'garlic q) (alwayso))
((== 'onion q)))
(== 'onion q))
'(onion)
> (run 2 q
(conde ((== 'garlic q) (alwayso))
((== 'onion q)))
(== 'onion q))
(帰ってこない)
これは、q
が'garlic
とunifyしたものがいっぱいでてくるけど
suspensionのおかげでconde
内部の(== 'onion q)
にも出番が回ってきて
一度だけ成功するってことだな
評価の順番は自信がない
conde
の方だけ評価してみる
garlic onion garlic garlic garlic …と予想
> (take-inf 5 ((conde ((== 'garlic q) (alwayso)) ((== 'onion q))) empty-s))
'(((#(q) . onion))
((#(q) . garlic))
((#(q) . garlic))
((#(q) . garlic))
((#(q) . garlic)))
おや
onion
の方が先に出てくるのか
そこらへんまでは見えてないなあ
onionにもalwayso
をつけてやれば何度も成功する
> (run 5 q
(conde ((== 'garlic q) (alwayso))
((== 'onion q) (alwayso)))
(== 'onion q))
'(onion onion onion onion onion)
こっちもconde
見ておく
> (take-inf 5 ((conde ((== 'garlic q) (alwayso)) ((== 'onion q) (alwayso))) empty-s))
'(((#(q) . garlic))
((#(q) . onion))
((#(q) . garlic))
((#(q) . onion))
((#(q) . garlic)))
こんどはgarlicが先かよ!