我自己在学习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).
1 回答
第二个子句中的切割是多余的,因为没有更多的子句,并且之前的目标(
is/2
调用)是确定性的 . 我也不认为剪切在尾递归优化中扮演任何角色(这基本上要求你递归调用是子句体中的最后一个目标) .但是,在担心削减位置之前,您应该检查如果在
nth(+,+,-)
以外的模式下调用nth/3
谓词会发生什么 . 例如,在模式nth(+,+,+)
中发生了什么,即当您实例化所有参数调用谓词时,但该元素不在列表中?提示:将剪切移动到第一个子句并不能解决问题 .