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

时间:2012-03-20 00:56:18

标签: list prolog clpfd instantiation-error

我做了一个Prolog谓词posAt(List1,P,List2)来测试PList1的{​​{1}}位置的元素是否相等:

List2

测试时:

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

我期望输出?- posAt([1,2,3], X, [a,2,b]). ,但我得到以下错误:

  

X = 2

为什么我收到此错误?

5 个答案:

答案 0 :(得分:9)

Prolog谓词是参数之间的关系和你的陈述

  

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

显然是可以使用多种解决方案的示例。

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1.

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

posAt([X0|_], Pos, Pos, [X1|_]) :-
    X0 == X1.

现在它按预期工作。

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1 ;
X = 3 ;
false.

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

posAt(L0, P, L1) :-
   nth1(P, L0, E),
   nth1(P, L1, E).

输出:

?- posAt([1,2,3],X,[1,5,3,7]).
X = 1 ;
X = 3.

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

答案 1 :(得分:7)

这是因为,当Prolog评估子目标K > 1时,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).

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

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

如果上述子句失败,因为列表元素X0X1不相等,则列表位置CurrPos加1,并且对posAt/4的递归调用开始再次处理下一对项目。

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

答案 2 :(得分:2)

此类问题的一般解决方案是约束

使用进行适用于所有方向的整数运算:

:- use_module(library(clpfd)).

posAt([X|_], 1, [X|_]).
posAt([_|X], K, [_|Y]) :-
   K #> 1, 
   Kr #= K - 1,
   posAt(X,Kr,Y).

通过这些简单的更改,您的示例完全按预期工作:

?- posAt([1,2,3], X, [a,2,b]).
X = 2 ;
false.

答案 3 :(得分:2)

(这只是在我的仪表板上弹出,因此迟到的答案......)

我查看了这个问题,并在考虑是否有可能提供接近原始问题的解决方案。正如已经解释的那样,问题是关系>需要实例化其参数。实际上is类似。但是,通过重新排序目标可以很容易地解决这个问题:

posAt([X|_], 1, [X|_]).
posAt([_|X], K, [_|Y]) :-
   posAt(X, Kr, Y),
   K is Kr+1,
   K > 1.

这个解决方案是,只要K被接地,运行时在两个列表的长度上都是线性的。但是,如果第一个元素在列表中匹配,则会出现问题,如重复答案中所示。

事实上,最后一个元素是多余的,因此是等价的。

posAt([X|_], 1, [X|_]).
posAt([_|X], K, [_|Y]) :-
   posAt(X, Kr, Y),
   K is Kr+1.

然而,正如@repeat证明的那样,这段代码非常慢。这可能是因为代码破坏了尾递归。

逻辑清洁解决方案可以解决此问题。在这里,我们将使用Peano Axiomes(s / 1后继者或关系)代表自然数字,解决方案将成为

posAt([X|_], zero, [X|_]).
posAt([_|X], s(K), [_|Y]) :-
   posAt(X, K, Y).

然而,这很难及时,因此, hackish 解决方案大致相当于

  posAt([X|_], [a], [X|_]).
  posAt([_|X], [a|L], [_|Y]) :-
      posAt(X, L, Y).

此解决方案的时间安排

N=8000,numlist(1,N,_Zs), length(_LN,N),time(posAt(_Zs,_LN,_Zs)).
 7,999 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 7342035 Lips)
N = 8000

答案 4 :(得分:2)

TL; DR: @CAFEBABE@CapelliC@mat@sharky 全部的答案落空短!

那么...... 完全是前面提出的答案的缺点?

  • @ CAFEBABE'陈述:

      

    这个解决方案的好处是运行时在两个列表的长度上是线性的。

    让我们把这个陈述付诸实践!

    ?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1000,Zs)).
    % 999,001 inferences, 0.090 CPU in 0.091 seconds (100% CPU, 11066910 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 4 inferences, 0.000 CPU in 0.000 seconds (97% CPU, 66738 Lips)
    false.
    

    无赖!其他人做得很好:

    ?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1000,Zs)).
    % 671 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 3492100 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
    
    ?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1000,Zs)).
    % 3,996 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 3619841 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 5 inferences, 0.000 CPU in 0.000 seconds (89% CPU, 154703 Lips)
    false.
    
    ?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1000,Zs)).
    % 1,000 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 2627562 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 4 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 97109 Lips)
    false.
    
  • @CapelliC使用nth1/3,这可能(并确实)导致通用终止问题:

    ?- time((posAt__CapelliC1(_,N,[a,b,c]), false)).
    **LOOPS**
    

    d'哦!其他人都做得很好:

    ?- time((posAt__CAFEBABE1(_,_,[a,b,c]), false)).
    % 14 inferences, 0.000 CPU in 0.000 seconds (88% CPU, 1098470 Lips)
    false.
    
    ?- time((posAt__mat1(_,_,[a,b,c]), false)).
    % 2,364 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 2764075 Lips)
    false.
    
    ?- time((posAt__sharky1(_,_,[a,b,c]), false)).
    % 6 inferences, 0.000 CPU in 0.000 seconds (89% CPU, 207247 Lips)
    false.
    
  • @ mat的代码存在复杂性问题。 @CAFEBABE和@CapelliC做"好一点" - 他们的代码更快,因为他们使用依赖于较低级别的原语(is)/2nth1/3。 / p>

    ?- numlist(1,1000,Zs), time((posAt__mat1(Zs,_,_), false)).
    % 33,365,972 inferences, 1.643 CPU in 1.643 seconds (100% CPU, 20304661 Lips)
    false.
    
    ?- numlist(1,1000,Zs), time((posAt__CAFEBABE1(Zs,_,_), false)).
    % 1,001,002 inferences, 0.083 CPU in 0.083 seconds (100% CPU, 12006557 Lips)
    false.
    
    ?- numlist(1,1000,Zs), time((posAt__CapelliC1(Zs,_,_), false)).
    % 171,673 inferences, 0.030 CPU in 0.030 seconds (100% CPU, 5810159 Lips)
    false.
    

    @sharky的代码在这方面显然是最好的:

    ?- numlist(1,1000,Zs), time((posAt__sharky1(Zs,_,_), false)).
    % 1,003 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1605658 Lips)
    false.
    
  • @ sharky的代码使用元逻辑内置谓词(==)/2,这使得它在使用不充分实例化的术语时会失去逻辑健全性。此查询应该成功:

    ?- posAt__sharky1([a], 1, Xs).
    false.
    

    其他代码都给出了一个逻辑上合理的答案:

    ?- posAt__CAFEBABE1([a], 1, Xs).
    Xs = [a|_G235] ;
    false.
    
    ?- posAt__CapelliC1([a], 1, Xs).
    Xs = [a|_G235].
    
    ?- posAt__mat1([a], 1, Xs).
    Xs = [a|_G235] ;
    false.
    
  • 过去第一个答案,@ CAFEBABE的代码多一点效率低下:

    ?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1,Zs)).
    % 0 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 0 Lips) 
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 999,004 inferences, 0.076 CPU in 0.076 seconds (100% CPU, 13121058 Lips)
    false.
    

    与@ sharky的代码相似 - 但是要小一个数量级的问题:

    ?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1,Zs)).
    % 1 inferences, 0.000 CPU in 0.000 seconds (75% CPU, 31492 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 1,003 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1078556 Lips)
    false.
    

    @CapelliC和@mat的代码都做得很好:

    ?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1,Zs)).
    % 7 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 306802 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
    
    ?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1,Zs)).
    % 0 inferences, 0.000 CPU in 0.000 seconds (80% CPU, 0 Lips)
    Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
    % 5 inferences, 0.000 CPU in 0.000 seconds (84% CPU, 345662 Lips)
    false.
    

那么......我们该怎么办? 为什么不关注 this approach 并将@ mat&s和@ sharky的代码结合起来?

:- use_module(library(clpfd)).

posAt__NEW(L0, Pos, L1) :- 
    posAt__NEW_(L0, 1, Pos, L1).

posAt__NEW_([X|_], Pos, Pos, [X|_]).
posAt__NEW_([_|X0s], CurrPos, Pos, [_|X1s]) :-
    CurrPos #< Pos,
    NextPos #= CurrPos + 1,
    posAt__NEW_(X0s, NextPos, Pos, X1s).

让我们使用posAt__NEW/3重新运行上面的示例查询:

?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1000,Zs)).
% 4,997 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 18141619 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 9 inferences, 0.000 CPU in 0.000 seconds (71% CPU, 122877 Lips)
false.

?- time((posAt__NEW(_,_,[a,b,c]), false)).
% 440 inferences, 0.001 CPU in 0.001 seconds (98% CPU, 803836 Lips)
false.

?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false)).
% 154,955 inferences, 0.014 CPU in 0.014 seconds (100% CPU, 11067900 Lips)
false.

?- posAt__NEW([a], 1, Xs).
Xs = [a|_G229] ;
false.

?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1,Zs)).
% 1 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 121818 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 7 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 266748 Lips)
false.

好的!最后,我们确保上面3 rd 查询中使用的目标具有线性复杂性:

?- numlist(1,100,Zs), time((posAt__NEW(Zs,_,_), false)).
% 15,455 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 3545396 Lips)
false.

?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false)).
% 154,955 inferences, 0.016 CPU in 0.017 seconds (98% CPU, 9456629 Lips)
false.

?- numlist(1,10000,Zs), time((posAt__NEW(Zs,_,_), false)).
% 1,549,955 inferences, 0.098 CPU in 0.099 seconds (99% CPU, 15790369 Lips)
false.

?- numlist(1,100000,Zs), time((posAt__NEW(Zs,_,_), false)).
% 15,499,955 inferences, 1.003 CPU in 1.007 seconds (100% CPU, 15446075 Lips)
false.