1

我正在编写一个 Prolog 谓词,它将前三个元素从编号列表中删除并打印结果。编号列表的示例:

[e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)].

普通列表的原始谓词如下所示:

strim([H|T],R) :-   
   append(P,R,[H|T]),  
   length(P,3).

因此,由于长度谓词也适用于编号列表,因此我只需要编写将一个编号列表附加到另一个列表的谓词:

compose([],L,[L]).
compose([e(F,C)|T],e(A,_),[e(F,C)|L]) :-
   N is C+1,
   compose(T,e(A,N),L).

napp(X,[],X).
napp(L,[e(X,Y)|T],M):-
   compose(L,e(X,Y),L1),
   napp(L1,T,M).

我希望编号列表的谓词是普通列表谓词的略微修改版本,所以我写了这个:

numstrim([e(X,Y)|T],R) :-
   napp(P,R,[e(X,Y)|T]),
   length(P,3).

但是,我收到此错误:

ERROR: compose/3: Arguments are not sufficiently instantiated

有人可以解释导致错误的原因以及如何避免它吗?我是 Prolog 的新手。

4

1 回答 1

2

实例化错误是使用模式谓词的 Prolog 程序中的常见现象:这些谓词只能在特殊情况下使用,例如要求某些参数完全实例化等。

作为初学者,我认为建议您改用更通用的谓词,这样您就可以自由地交换目标的顺序,而不必考虑程序限制,至少不要那么早,并且没有能力自由地试验你的代码。

例如,在您的情况下,以下微不足道的更改compose/3为您提供了一个适用于所有方向的谓词:

撰写([],L,[L])。
撰写([e(F,C)|T],e(A,_),[e(F,C)|L]):-
        N #= C+1 ,
        撰写(T,e(A,N),L)。

在这里,我简单地用 CLP(FD) 约束替换了模式谓词它完全包含了整数上的更底层谓词。(is)/2 (#=)/2

在这个小改动之后(取决于你的 Prolog 系统,你可能需要导入一个库来使用更通用的算术谓词),我们得到:

?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es) .
不终止

因此,我们发现实例化错误实际上掩盖了一个只能从程序上理解的不同问题,现在它已经曝光。

为了改善这一点,我现在转过两个目标numstrim/2

numsrim([e(X,Y)|T], R) :-
        长度(P,3),
        纳普(P,R,[e(X,Y)|T])。

这是因为length(P, 3) 总是终止,并且放置一个总是首先终止的目标最多可以改善而不是恶化纯单调逻辑程序的终止属性。

所以现在我们得到:

?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es) .
Es = [e(b, _1442), e(a, _2678), e(r, _4286)] 。

也就是说,至少我们现在得到了答案

然而,谓词仍然没有 普遍终止,因为我们得到:

?- numstrim([e(f,1),e(o,2),e(o,3),e(b,4),e(a,5),e(r,6)], Es) ,的。
不终止

我把解决这个问题留作练习。

于 2016-10-28T08:45:24.880 回答