kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

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しようとして失敗する
alwaysoconde節がもうひとつあったことを思い出してもう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が先かよ!