我自己在学习Prolog,最近发现了一条笔记: -
示例:nth / 3
- 例如,要查找列表的第n个元素,我们可以使用
nth([X|_],0,X).
nth([_|L],N,X) :- N1 is N - 1, nth(L,N1,X).
列表的第0个元素是列表的头部(第一个子句),否则 我们取列表尾部的第n-1个元素(第二个子句)。
一旦我们找到了第n个元素,我们就无法通过回溯来找到它。
nth([X|_],0,X).
nth([_|L],N,X) :- N1 is N - 1, !, nth(L,N1,X).
- 添加切口使其清晰,可能是尾递归所必需的 优化
然而,当我在Prolog中使用trace函数时,我发现这两段代码的调用序列完全相同。
我应该把!改为标记如下?
nth([X|_],0,X) :- !.
nth([_|L],N,X) :- N1 is N - 1, nth(L,N1,X).
答案 0 :(得分:2)
第二个子句中的剪切是多余的,因为没有更多的子句,而它之前的目标(is/2
调用)是确定性的。我也不认为剪切在尾递归优化中扮演任何角色(这基本上要求你递归调用是子句体中的最后一个目标)。
但是,在担心削减展示位置之前,您应该检查如果以nth/3
以外的模式调用nth(+,+,-)
谓词会发生什么。例如,模式nth(+,+,+)
中发生了什么,即当你实例化所有参数调用谓词时,但元素不在列表中?提示:将剪切移动到第一个子句并不能解决问题。