(teacupo x)
意思是“成功两次:一次与x
统一tea
,第二次与x
统一cup
”。然后,
(conde
((teacupo x) (= #t y) #s)
((= #f x) (= #t y)) ; you had a typo here
(else #u)
方法,
- 对于由 产生的每个解决方案
(teacupo x)
,也统一y
并#t
成功;并且
- 对于由 产生的每个解决方案
(= #f x)
,也统一y
并#t
成功;并且
- 不再产生解决方案
所以每个x
in(tea cup)
与y
in配对(#t)
,并且x
in与in(#f)
配对,形成;然后被报告,即收集到解决方案的最终结果列表中,给出.y
(#t)
r
r
( (tea #t) (cup #t) (#f #t) )
“看来,teacupo 一次只放弃了一种解决方案。”
是的,这在概念上是完全正确的。
“一行成功后,假装失败,刷新变量,找到下一行成功。”
是的,但是如果条件(或后续目标)成功多次,则每行都可以成功多次。
“似乎该代码中的 conde 回到了成功的行,然后迫使 teacupo conde 失败并放弃下一个可能的值。”
它实际上准备提前生成它们(但作为一个流,而不是作为一个列表),然后每个都被单独处理,通过整个后续步骤链进行馈送,直到成功到达最后一步,或者链中断,被一个#u
或其他失败的目标打断。因此,当前一个的处理完成时,将尝试下一个。
在伪代码中:
for each x in (tea cup):
for each y in (#t): ; does _not_ introduce separate scope for `y`;
collect (x y) ; `x` and `y` belong to the same logical scope
for each x in (#f): ; so if `x` is used in the nested `for` too,
for each y in (#t): ; its new value must be compatible with the
collect (x y) ; one known in the outer `for`, or else
for each _ in (): ; it will be rejected (x can't be two different
collect (x y) ; things at the same time)
至于为什么它会这样工作,我可以指出我的另一个答案,这可能会有所帮助(尽管它不使用 Scheme 语法)。
使用它,作为说明,我们可以将您的测试编写为 Haskell 代码,它实际上在功能上等同于我认为的书的代码(当然,在这种特定情况下),
data Val = Fresh | B Bool | S String | L [Val] deriving Show
type Store = [(String,Val)]
teacupo x = unify x (S "tea") &&: true -- ((= tea x ) #s)
||: unify x (S "cup") &&: true -- ((= cup x ) #s)
||: false -- (else #u)
run = [[("r", Fresh)]] -- (run* (r) ......
>>: (\s -> [ s ++: [("x", Fresh), ("y", Fresh)] ]) -- (fresh (x,y)
>>: -- (conde
( teacupo "x" &&: unify "y" (B True)
&&: true -- ((teacupo x) (= #t y) #s)
||: unify "x" (B False) &&: unify "y" (B True) -- ((= #f x) (= #t y))
||: false -- (else #u)
)
&&: project ["x", "y"] (unify "r" . L) -- (= r (list x y))
>>:
reporting ["r"] -- ...... )
reporting names store = [[a | a@(n,_) <- store, elem n names]]
只需最低限度的实现,就足以使上述代码工作,
project vars kont store =
kont [val | var <- vars, (Just val) <- [lookup var store]] store
unify :: String -> Val -> Store -> [Store]
unify sym val store =
let
(Just v) = (lookup sym store)
in
case (val_unify v val) of
Just newval -> [replace_val sym newval store] -- [updated store], if unifies
Nothing -> [] -- couldn't unify - reject it
val_unify v Fresh = Just v -- barely working,
val_unify Fresh v = Just v -- initial
val_unify (B v) (B u) | v == u = Just (B v) -- implementation
| otherwise = Nothing
val_unify (S v) (S u) | v == u = Just (S v)
| otherwise = Nothing
val_unify _ _ = Nothing
replace_val s n ((a,b):c) | s == a = (a,n) : c
| otherwise = (a,b) : replace_val s n c
产生输出
*Main> 运行
[[("r", L [S "tea",B True])], [("r", L [S "cup",B True])], [("r", L [B 假,B 真])]]
如果我们将翻译后的conde
表达式中的第二行更改为
||: unify "x" (B False) &&: unify "x" (B True) -- ((= #f x) (= #t x))
我们确实只得到了两个结果,
*Main> 运行
[[("r", L [S "tea",B True])], [("r", L [S "cup",B True])]]