我有这个问题,我需要提供一个解决方案,以避免两个子句中的递归调用f(T,S)
:
f([],0).
f([H|T],S):-
f(T,S1),
S1>=2,
!,
S=S1+H.
f([_|T],S):-
f(T,S1),
S=S1+1.
我不明白这是做什么的...... 我真的不知道如何避免这种递归调用。 请帮我解决方案
答案 0 :(得分:0)
注意:我用L = M + N
替换了L is M + N
形式的命题,因为我没有使用Turbo Prolog,但我猜其他一切都是一样的。
你的f/2
谓词很奇怪。第三个子句只计算列表的长度但是
第二个将S1与列表的尾部相关联,并将为S1确定的值加到头部的值如果 S1>换句话说,如果尾部> 1,则f/2
将头部加到尾部的长度上。 1,否则它只返回列表的长度(即1或2);如,
?- f([1], X).
X = 1.
?- f([2], X).
X = 1.
?- f([2,1], X).
X = 2.
?- f([3,1], X).
X = 2.
?- f([3,1,1], X).
X = 5.
?- f([2,1,1], X).
X = 4.
f/2
的第二和第三个条款描述了完全不同的关系。第二个谓词将列表头部的整数值与列表正文的长度相关联,提供某个条件。第三个谓词简单地将整数与列表相关联,使得整数的值与列表中的元素的数量相同。即,它描述了列表的长度。 Prolog擅长声明性编程,并通过强迫/使我们能够写出清晰简洁的关系描述来帮助我们理解问题。 f/2
的第二和第三个条款描述了不同的关系,因此我们可以(并且应该)使用两个不同的谓词。正如您将看到的,这将允许我们从谓词f/2
中删除递归调用,因为递归只是确定长度关系所必需的(但我们仍然在操作中递归,它只是不是递归的致电f/2
)。这是一个可能的解决方案(它只使用内置的length/2
,但如果不允许使用内置函数,则可以用自己的谓词替换它:)
f([], 0).
f([H|T],S):-
length(T, Len), % Len is the length of T
( Len > 1 % if Len is greater than 1
->
S is Len + H % then the value of S is Len plus the value of H
;
S is Len + 1 % otherwise, S is Len + 1 ( the addition is to make up for the missing H)
).
你实际上可以进一步折射以消除条件:
head_plus_length_of_tail([E1, E2 | Es], N) :-
length([E2|Es], Len),
N is E1 + Len.
g(List, N) :-
head_plus_length_of_tail(List, N), !.
g(List, N) :-
length(List, N).
head_plus_length_of_tail / 2只有在列表中有三个或更多元素时才会成功(它会处理条件,检查列表正文的长度是否为> 1.如果成功,我们剪切,所以它赢了' t backtrack也给我们列表的长度。否则我们只得到列表的长度。