我正在尝试实现一些简单的谓词,比如 my_length 或 my_append。
如果我们事先知道我们想要找到一个列表的长度,或者我们想要追加两个列表,这对我来说很容易。 (即我知道什么是输入,什么是输出)。
在 Prolog 中,可以用其他方式做事。像 my_length(L, 3) 或 my_append(A,B,[1,2,3])。
有时,我的代码可以工作。有时,它没有。
我发现很难确保它以各种不同的方式工作。除非它只是我自己的辅助谓词,否则您永远不会真正知道您的用户想要用什么来测试它。有时问题甚至可能定义不明确,例如
my_length(L, 5)
输出什么是不清楚的。
有什么最佳实践吗?
对于实际编程,我发现忽略这些其他方式并只关注特定的调用方式要容易得多。这就是我完成工作的方式,我只是担心其他人可能会以不同的方式称呼它。
我有办法在语言层面做出限制吗?或者我应该?
特别是,我正在尝试编写
my_length
使其适用于
my_length([], 0).
my_length([_|T], A) :- my_length(T, TA), A is TA + 1.
这两种方式都很好,除了当我问相反的问题时它会提示更多答案,然后我们得到堆栈溢出。我们也不能对长度参数进行算术运算,因为它可能未指定。
这只是个案。
可以用cut(即感叹号):
list_length(Lst, Len) :-
nonvar(Len),
% Commit to this path
!,
% Using an accumulator - faster than recursion
list_length_(Lst, 0, Len),
% No more than 1 solution
!.
list_length(Lst, Len) :-
list_length_(Lst, 0, Len).
% Found end of list
list_length_([], Len, Len).
list_length_([_|T], Upto, Len) :-
% Iterate through list
Upto1 is Upto + 1,
list_length_(T, Upto1, Len).
swi-prolog 中的结果:
?- list_length([a,b,c], Len).
Len = 3.
?- list_length(Lst, 3).
Lst = [_, _, _].
?- Lst = [a,b,c], list_length(Lst, Len).
Len = 3.
这避免了不必要的选择点。