Reasoned Schemer (109) conda
なんだか/o
で完結したみたいな気分になってましたが
ここで少し流れが変わってconda
、condu
が登場
ここらへん、“The Second Commandment”が何を言っているのかよくわからなかった記憶
ひさしぶりに処理系の中身と関連付けながら見ていく
こんどはわかるかな
conda
の定義
(define-syntax conda
(syntax-rules ()
((conda (g0 g ...)) (conj g0 g ...))
((conda (g0 g ...) ln ...)
(ifte g0 (conj g ...) (conda ln ...)))))
conda
のそれぞれの節の最初のgoalを条件にしてifte
に展開していく
ifte
の定義
(define (ifte g1 g2 g3)
(lambda (s)
(let loop ((s-inf (g1 s)))
(cond
((null? s-inf) (g3 s))
((pair? s-inf)
(append-map-inf g2 s-inf))
(else (lambda () (loop (s-inf))))))))
questionが失敗だったら残りのconda
節を評価
questionが成功だったらその結果をもってanswerをappend-map-inf
する
append-map-inf
するというのはconj2
するということと同じ
answerもconj
されてるから結果的には対象となるconda
節のgoalをすべてconj
することになる
そして残りのconda
節は無視される
questionがsuspensionだったら評価してもう一度
not-pastao
(defrel (not-pastao x)
(conda ((== 'pasta x) fail)
(succeed succeed)))
からの
> (run* x (conda ((not-pastao x) fail)
((== 'spaghetti x) succeed)))
'(spaghetti)
まずnot-pastao
の中の(== 'pasta x)
が成功
成功したのでいったんx == 'pasta
となるけど
けっきょくnot-pastao
としてはfail
するのでこの束縛は上位には伝わらず
x
はfreshなまま
でx == 'spaghetti
で成功
これはこれでいいのか?
x == 'spaghetti
なら(not-pastao x)
が成功してconda
的にはそこでfail
するはず、とも言えそうな
続いて
> (run* x (== 'spaghetti x)
(conda ((not-pastao x) fail)
((== 'spaghetti x) succeed)))
'()
x == 'spaghetti
なら(not-pastao x)
が成功してconda
的にはそこでfail
する、
と見れば普通
さっきのがNGでこっちはOKってことなの?
(),
because(not-pastao x)
succeeds, which shows the risks involved when usingconda
. We can’t allow a fresh variable to become associated as part of aconda
question.
()です。
なぜならば、(not-pastao x)
が成功するからです。これは、conda
を使うときに巻き込まれるリスクを示しています。我々は、conda
のquestionの一部としてfreshな変数をassociateさせてはなりません。
これがつまりThe Second Commandmentの言ってることなんだけど
最初に読んだときはここで、さっきのはOKだけど今度のはダメ、って書いてあると思ったんだよな
ここが勘違いだった?
x
がfreshだと、not-pastao
の(== 'pasta x)
が成功してx == 'pasta
にしてしまうからダメと言っているのか
freshだと==
が成功してしまうから比較にはならないと
そういうことだなきっと
値が決まってから判定するような使い方するってことね