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)...)
因此,链条的最终目标是一个简单的目标。 这实际上没有什么限制,因为condAforms的最后一个语句和简单的“ 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做什么。