避免递归调用Prolog

时间:2014-01-12 12:24:07

标签: prolog

我有这个问题,我需要提供一个解决方案,以避免两个子句中的递归调用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.

我不明白这是做什么的...... 我真的不知道如何避免这种递归调用。 请帮我解决方案

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也给我们列表的长度。否则我们只得到列表的长度。