我正在Prolog练习。我已经实现了类似于length/2
的谓词(此处称为ue_length
),如下所示:
%%
% ue_length/2
%%
% not a list predicate
\+(T) :- call(T), !, fail.
\+(_).
% target case
ue_length(List, Length) :- \+(is_list(List)), !, fail.
ue_length(List, Length) :- ue_length(List, 0, Length).
% standard cases
ue_length([], Length, Length).
ue_length([X], Part, Length) :- ue_length([], [Part], Length).
ue_length([X| Rest], Part, Length) :- ue_length(Rest, [Part], Length).
结果应该是一个术语而不是一个数字:0
为[]
,[0]
为长度为1且[...[0]...]
的列表n
}括号)获取长度为n
的列表。
当我用例如Prolog(SWI-Prolog 6)查询时[1,2,3,4,5]
我得到了两次正确的结果。
?- ue_length([1,2,3,4,5], X).
X = [[[[[0]]]]]
X = [[[[[0]]]]].
我是Prolog的新手。有人可以解释为什么我会得到多余的结果吗?
答案 0 :(得分:3)
首先,减小查询的大小。仅ue_length([1], X).
就可以观察到相同的问题(冗余解决方案)。
但还有其他问题更多:
?- ue_length(L,N).
false.
所以你的定义用列表[1]
成功但是在它的位置失败了吗?这根本没有任何意义!即使循环也是一种更好的行为。
另一个有问题的案例是
?- ue_length(L,0).
false.
此处,您的定义应以L = []
作为答案。
这是使用is_list/1
的测试的罪魁祸首。只需删除规则
ue_length(List, Length) :- \+(is_list(List)), !, fail. % incorrect!
现在,您的定义也可用于询问最常见的查询,其中包含参数中的不同变量。
?- ue_length(L,N).
L = [], N = 0
; L = [_A], N = [0]
; L = [_A], N = [0]
; L = [_A, _B], N = [[0]]
...
这是Prolog的一个非常好的属性:您不需要为测试用例输入具体数据。只需像专业人士一样输入最常见的查询,Prolog将为您完成其余的工作。
false
要将此冗余本地化,首先要考虑如何发生这种情况。一个简单的可能性是程序中的某些子句是冗余的,因此可以删除。
让我们说它是最后一个。因此,我会在最后一个条款中插入一个 false
目标。我再次尝试最常见的查询。唉......
ue_length(List, Length) :- ue_length(List, 0, Length). % standard cases ue_length([], Length, Length). ue_length([_X], Part, Length) :- ue_length([], [Part], Length).ue_length([_X| Rest], Part, Length) :-false,ue_length(Rest, [Part], Length). ?- ue_length(L,N). L = [], N = 0 ; L = [_A], N = [0] ; false.
该规则必须非常重要,因为现在我们只获得长度为零和一的列表的答案。所以我猜错了。但我的观点是,只需使用最常用的查询,您就可以轻松地看到这一点。实际的冗余条款是另一个。并且不要忘记询问最一般的查询,以确保您能得到所有答案!