我现在想运行tarai,在Prolog中的内容如下。一个测试案例是运行?- tarai(12,6,0,X)
。这是一个相当困难的测试案例,例如,GNU Prolog与此测试案例一起崩溃。
tarai(X, Y, Z, R) :-
X > Y ->
X1 is max(0,X-1), tarai(X1, Y, Z, Rx),
Y1 is max(0,Y-1), tarai(Y1, Z, X, Ry),
Z1 is max(0,Z-1), tarai(Z1, X, Y, Rz),
tarai(Rx, Ry, Rz, R);
R = Y.
我最感兴趣的是测试用例是否可以在tarai的miniKanren代码的完全声明版本上运行。可选地,我会对向后运行一些测试用例感兴趣。
我有点茫然。我设法安装了guile(一种方案变体),并且可以成功运行miniKanren测试用例。但是miniKanren没有整数,那该怎么办?
答案 0 :(得分:1)
这个问题被问到如何在prolog规范中实现tarai函数的更通用版本,该版本允许x,y,z字段中的变量。此处的技术可以例如以序言形式实现。 clpfd有限域求解器和kanren需要类似的东西(上面的注释讨论,例如对numbers.scm的引用)。关键是在所有情况下使用nuke->并使用防护,我们将假设> o = o <= o均已为变量定义(例如,对于var X,X> 0将约束X为值1,2 ,3,...)。我们还将假设使用间隔算术约束通过特殊的“ iso”为此类变量定义了“ -o”。使用此方法,我们可以将tarai定义为以下代码(如果将max和min也定义为约束,则可以简化,但是这里我们通过不等式和大量案例来实现)。
(define (taray x y z w)
(lambda ()
(conde ((<o x y)
(fresh (rx ry rz)
(conde
((conde
((>o x 0)
(fresh (xx)
(conde
((iso xx (-o x 1))
(tarai xx y z rx)))))
((== x 0) (tarai 0 y z rx)))
(conde
((>o y 0)
(fresh (yy)
(conde
((iso yy (-o y 1))
(tarai yy z x ry)))))
((== y 0) (tarai 0 z x ry)))
(conde
((>o z 0)
(fresh (zz)
(conde
((iso zz (-o z 1))
(tarai zz x y rz)))))
((== z 0) (tarai 0 x y r<)))
(tarai rx ry rz r)))))
((>=o x y) (== x y))))))
答案 1 :(得分:1)
我是guile-log的开发者,它是一个基于guile方案的逻辑编程环境,该环境同时具有minikanren构造和prolog构造,并且可以将它们混合使用。它还移植了一个clpfd库,因此您可以在此处执行以下操作(不幸的是,atm无法正常工作(我正在研究的错误))。假设已导入clpfd。 (,; ;;像kans一样交错kanren)。用和替换;;;与;您会使用clpfd库获得可以在swi prolog等代码上运行的代码。
tarai(X,Y,Z,W) :-
(
X #> Y ,
(
(
((X #> 0 , XX #= X - 1, tarai(XX,Y,Z,RX)) ;;
(X = 0 , tarai(0,Y,Z,RX))) ,,
((Y #> 0 , YY #= Y - 1, tarai(YY,Z,X,RY)) ;;
(Y = 0 , tarai(0,Z,X,RY))) ,,
((Z #> 0 , ZZ #= Z - 1, tarai(ZZ,X,Y,RZ)) ;;
(Z = 0 , tarai(0,X,Y,RZ)))
) ,,
tarai(RX,TY,RZ,R)
)
) ;;
(X #=< Y, R=Y).
答案 2 :(得分:0)
例如,我尝试使用clpfd运行tarai(12,X,0,12),但这很复杂。记忆功能不适用于swipl的属性变量。因此,我能找到的最佳解决方案是将确定性的记住的tarai与类似的东西一起使用
tarai2(X,Y,Z,W) :-
(var(X)->between(0,20,X);true),
(var(Y)->between(0,20,Y);true),
(var(z)->between(0,20,Z);true),
tarai(X,Y,Z,W).
然后可以容易地找到该范围内具有tarai2(12,Y,Z,12)的所有解Y,Z。
答案 3 :(得分:-1)
请注意,此算法只有一种解决方案(如果存在)并且是确定性的。您可以将方案变量x,y,z直接传递给kanren tarai函数,因为它们没有统一性,因此无需kanren变量就可以实现X,Y,Z的逻辑。但是R值必须是逻辑变量,您需要以tarai(Rx,Ry,Rz,R)的形式获取有界值,例如查找Rx,Ry,Rz的值,并将其输入tarai函数。另外,您还需要确保在前三个表单完成后执行此表单(这很容易完成,因为没有纯粹的多重选择),因此您知道Rx,Ry,Rz是有界的。还要注意,该算法可能依赖于执行顺序才能有效执行,但是确定性又意味着这一点很容易满足。注意A-> B; C在这里简单地转换为方案(如果A B C的话),因为A = X> Y是确定性的。因此代码可能看起来像是伪代码
(define (tarai x y z r)
(lambda ()
(fresh (rx ry rz)
(if (> x y)
(conda
( (conda ((tarai (- x 1) y z rx)
(tarai (- y 1) z x ry)
(tarai (- z 1) x y rz)))
(project (rx ry rz) (tarai rx ry rz r))))
(== r y)))))
答案 4 :(得分:-1)
要在guile-log方案宏接口see links on this site中进行确定性验证,您可以通过备忘实现,因为(没有备忘,解决方案将变量栈吹到guile-log上)
(define tarai
(memo
(<lambda> (x y z r)
(if (> x y)
(<var> (rx ry rz)
(<and>
(tarai (max (- x 1) 0) y z rx)
(tarai (max (- y 1) 0) z x ry)
(tarai (max (- z 1) 0) x y rz)
(tarai (<lookup> rx) (<lookup> ry) (<lookup> rz) r)))
(<=> r y)))))
scheme@(guile-user)> ,time (<run> 1 (r) (tarai 12 6 0 r))
$13 = (12)
;; 0.293411s real time, 0.290711s run time. 0.000000s spent in GC.
scheme@(guile-user)>
答案 5 :(得分:-1)
这是一个缓慢的实现,它是声明性的,并使用numbers.scm(由问题的作者建议)和minkanren。
(load "minkanren.scm)
(load "numbers.scm")
(define one (build-num 1))
(define zero (build-num 0))
(define (tarai x y z r)
(conde
((<=o x y) (== r y))
((<o y x)
(fresh (rx ry rz)
(conde
((fresh (xx)
(conde
((<o zero x) (minuso x one xx) (tarai xx y z rx))
((== zero x) (tarai zero y z rx))))
(fresh (yy)
(conde
((<o zero y) (minuso y one yy) (tarai yy z x ry))
((== zero y) (tarai zero z x ry))))
(fresh (zz)
(conde
((<o zero z) (minuso z one zz) (tarai zz x y rz))
((== zero z) (tarai zero x y rz))))
(tarai rx ry rz r)))))))
如果推导方向相反(因此我们要加上数字),由于声明式的样式,我们仍然可以解决
tarai(4,2,Z,4):, (you need to make binaries of the number) will lead to
Y = [0, 1],
W = [0, 0, 1],
Z = [0, 0, 1],
X = [0, 0, 1].
并且应该添加制表符:
tarai(12,6,0,W):
Z = (),
X = [0, 0, 1, 1],
Y = [0, 1, 1],
W = [0, 0, 1, 1].