简单的prolog程序.获取错误:>/2:参数未充分实例化

use*_*812 10 list prolog clpfd instantiation-error

余由Prolog的谓词posAt(List1,P,List2),在测试位置是否在元件PList1List2是相等的:

posAt([X|Z], 1, [Y|W]) :-
   X = Y.
posAt([Z|X], K, [W|Y]) :-
   K > 1,
   Kr is K - 1,
   posAt(X, Kr, Y).
Run Code Online (Sandbox Code Playgroud)

测试时:

?- posAt([1,2,3], X, [a,2,b]).
Run Code Online (Sandbox Code Playgroud)

我期望输出,X = 2但我得到以下错误:

ERROR: >/2: Arguments are not sufficiently instantiated

为什么我收到此错误?

Cap*_*liC 9

Prolog谓词是参数和语句之间的关系

List1和List2的位置P处的元素相等

显然是多种解决方案可行的例子.

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1.
Run Code Online (Sandbox Code Playgroud)

因此,sharky的答案清楚地解释了为什么出现技术错误,需要进行小的修正:

posAt([X0|_], Pos, Pos, [X1|_]) :-
    X0 == X1.
Run Code Online (Sandbox Code Playgroud)

现在它按预期工作.

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1 ;
X = 3 ;
false.
Run Code Online (Sandbox Code Playgroud)

为列表处理编写简单的谓词,这是一个非常有价值的学徒实践,也是有效学习语言的主要方式.如果您还倾向于研究可用的库谓词,这里是一个使用库中的nth1/3的版本(列表)

posAt(L0, P, L1) :-
   nth1(P, L0, E),
   nth1(P, L1, E).
Run Code Online (Sandbox Code Playgroud)

这输出:

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1 ;
X = 3.
Run Code Online (Sandbox Code Playgroud)

尝试理解为什么在这种情况下SWI-Prolog'顶级'解释器能够推断解决方案的确定性可能会很有趣.


sha*_*rky 7

这是因为,当K > 1Prolog评估子目标时,K仍然是未绑定的变量而不是数字.标准Prolog不能(不会)评估数值范围限制的真/假值,例如当它们不被研磨时(与CLP这样的约束求解器相反,它允许这种情况,但工作方式不同).

考虑这个解决方案

posAt(L0, Pos, L1) :- 
    posAt(L0, 1, Pos, L1).

posAt([X0|_], Pos, Pos, [X1|_]) :-
    X0 == X1.    
posAt([_|X0s], CurrPos, Pos, [_|X1s]) :-
    NextPos is CurrPos + 1,
    posAt(X0s, NextPos, Pos, X1s).
Run Code Online (Sandbox Code Playgroud)

第一个谓词posAt/3设置初始条件:列表为位置1,并调用posAt/4迭代列表.

第一个子句posAt/4是匹配条件:两个列表中相同位置的元素相等.在这种情况下,当前位置变量与Pos结果统一.

如果上面的子句因列表元素不正确X0而失败X1,则列表位置CurrPos加1,递归调用posAt/4再次开始处理下一对项目.

编辑:在第一个条款中删除了错误的剪切posAt/4(感谢@chac的拾取)