conda,condi,conde,condu
我正在阅读Reasoned Schemer 。
我有一些关于conde
如何工作的直觉。
然而,我无法findconde
/ condu
/ condu
/ condu
做什么的正式定义。
我知道https://www.cs.indiana.edu/~webyrd/,但似乎有例子,而不是定义。
conde
, condu
, condu
有什么正式的定义吗?
在Prolog的术语中, condA
是“软切” , *->
, condU
是“承诺select” – once
和软切的组合,所以(once(A) *-> B ; false)
表示切入 (A, !, B)
:
A *-> B ; C %% soft cut, condA once(A) *-> B ; C %% committed choice, condU
在condA
,如果目标A
成功了,所有的解决scheme都被传递给第一个子句B
并且没有可选的子句C
被尝试。 once/1
允许其论证目标只能成功一次(只保留一个解决scheme,如果有的话)。
condE
是一个简单的condI
,而condI
是一个在其组成部分的解决scheme之间交替的分离。
这里试图忠实地将本书的代码(无论是逻辑variables还是统一)翻译成18行Haskell(其中并置是curried函数应用程序,意思是cons )。 看看是否澄清事情:
- 顺序stream组合(本书的“
mplus
”):
(1) [] ++: ys = ys (2) (x:xs) ++: ys = x:(xs ++: ys)
- 交替stream组合(“
mplusI
”):
(3) [] ++/ ys = ys (4) (x:xs) ++/ ys = x:(ys ++/ xs)
- 顺序饲料(“
bind
”):
(5) [] >>: g = [] (6) (x:xs) >>: g = gx ++: (xs >>: g)
- 交替饲料(“
bindI
”):
(7) [] >>/ g = [] (8) (x:xs) >>/ g = gx ++/ (xs >>/ g)
- “
OR
” 目标组合(“condE
”):
(9) (f ||: g) x = fx ++: gx
- “交替
OR
”目标组合(“condI
”):
(10) (f ||/ g) x = fx ++/ gx
- “
AND
”目标组合(“all
”):
(11) (f &&: g) x = fx >>: g
- “交替
AND
”目标组合(本书的“allI
”):
(12) (f &&/ g) x = fx >>/ g
- 特殊的目标
(13) true x = [x] -- a sigleton list with the same solution repackaged (14) false x = [] -- an empty list, meaning the solution is rejected
目标产生(可能更新的)解决scheme的stream(可能是空的),给出一个问题(可能是部分的)解决scheme。
重新编写规则是:
(all) = true (all g1) = g1 (all g1 g2 g3 ...) = (\x -> g1 x >>: (all g2 g3 ...)) === g1 &&: (g2 &&: (g3 &&: ... )) (allI g1 g2 g3 ...) = (\x -> g1 x >>/ (allI g2 g3 ...)) === g1 &&/ (g2 &&/ (g3 &&/ ... ))
重写condX
规则是:
(condX) = false (condX (else g1 g2 ...)) = (all g1 g2 ...) === g1 &&: (g2 &&: (...)) (condX (g1 g2 ...)) = (all g1 g2 ...) === g1 &&: (g2 &&: (...)) (condX (g1 g2 ...) (h1 h2 ...) ...) = (ifX g1 (all g2 ...) (ifX h1 (all h2 ...) (...) ))
为了达到最终的condE
和condI
的翻译,没有必要实施本书的ifE
和ifI
,因为它们进一步简化为简单的操作符组合,所有操作符被认为是正确关联的 :
(condE (g1 g2 ...) (h1 h2 ...) ...) = (g1 &&: g2 &&: ... ) ||: (h1 &&: h2 &&: ...) ||: ... (condI (g1 g2 ...) (h1 h2 ...) ...) = (g1 &&: g2 &&: ... ) ||/ (h1 &&: h2 &&: ...) ||/ ...
所以在Haskell中不需要任何特殊的“语法”,简单的运算符就足够了。 可以使用任何组合,使用&&/
而不是&&:
如果需要的话。 但是OTOH condI
也可以被实现为接受要实现的目标的集合(列表,树等)的函数,这将使用一些聪明的策略来挑选它们中最可能或最需要的一个等等,而不仅仅是简单的二进制如||/
运算符(或书的ifI
)的交替。
接下来,本书的condA
可以用两个新的运算符( ~~>
和||~
来模拟,一起工作。 我们可以像例如一样自然地使用它们
g1 ~~> g2 &&: ... ||~ h1 ~~> h2 &&: ... ||~ ... ||~ gelse
这可以直观地理解为“ IF g1 THEN g2 AND ... OR-ELSE IF h1 THEN ... OR-ELSE gelse
”。
- “
IF-THEN
”目标组合是产生一个“尝试”的目标,必须以失败延续目标来调用:
(15) (g ~~> h) fx = case gx of [] -> fx ; ys -> ys >>: h
- 一个“尝试”目标和一个简单目标的“
OR-ELSE
”目标组合简单地将其“尝试”目标与第二个失败目标称为“失败”目标,所以它只不过是操作数自动分组的便利语法:
(16) (g ||~ f) x = gfx
如果||~
“ OR-ELSE
”运算符的结合能力比~~>
“ IF-THEN
”运算符的结合能力还要低,并且运算符的结合能力还不如&&:
上面例子的合理分组是自动生成的
(g1 ~~> (g2 &&: ...)) ||~ ( (h1 ~~> (h2 &&: ...)) ||~ (... ||~ gelse)...)
因此,链条的最终目标是一个简单的目标。 这实际上没有什么限制,因为condA
forms的最后一个语句和简单的“ AND
” – 它们的目标组合(或简单的false
也可以同样使用)是等价的。
就这样。 如果我们想要,我们甚至可以有更多types的尝试目标,由不同种类的“ IF
”运算符来表示:
- 在一个成功的条款中使用交替馈送(如果本书中有一个可以称为
condAI
):
(17) (g ~~>/ h) fx = case gx of [] -> fx ; ys -> ys >>/ h
- 使用成功的解决schemestream只产生一次 剪切效果,以build模
condU
:
(18) (g ~~>! h) fx = case gx of [] -> fx ; (y:_) -> hy
所以,最后,书的condA
和condU
的重写规则是简单的:
(condA (g1 g2 ...) (h1 h2 ...) ...) = g1 ~~> g2 &&: ... ||~ h1 ~~> h2 &&: ... ||~ ... (condU (g1 g2 ...) (h1 h2 ...) ...) = g1 ~~>! g2 &&: ... ||~ h1 ~~>! h2 &&: ... ||~ ...
理性的策略涵盖conda (软切)和道德 (承诺的select)。 你也可以在William Byrd 关于miniKanren的优秀论文中find他们的行为解释。 你已经标记这篇文章是关于core.logic。 要明确core.logic是基于一个比The Reasoned Schemer中提出的更新的miniKanren版本。 miniKanren总是交错分离的目标 – condi和交错变种不再存在。 conde现在是 condi 。
通过例子,使用core.logic:
conde将运行每个组,如果至less有一个组成功,则返回所有成功组的所有结果。
user> (run* [wq] (conde [u#] [(or* [(== w 1) (== w 2)]) (== q :first)] [(== q :second)])) ([_0 :second] [1 :first] [2 :first])
conda和conduit:在第一个成功的团队(从上到下)之后都会停止,
conda只返回来自第一个成功组的所有结果。
user> (run* [wq] (conda [u#] [(or* [(== w 1) (== w 2)]) (== q :first)] [(== q :second)])) ([1 :first] [2 :first])
只从第一个成功的小组返回一个结果。
user> (run* [wq] (condu [u#] [(or* [(== w 1) (== w 2)]) (== q :first)] [(== q :second)])) ([1 :first])
不知道condi做什么。