【问题标题】:Avoid recursive call Prolog避免递归调用 Prolog
【发布时间】:2014-01-19 05:18:42
【问题描述】:

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

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

【问题讨论】:

  • 任务不是避免non-tail递归调用吗?上面的代码是计算列表中元素的总和,没有递归就没有简单的方法(我不知道)。
  • 该谓词不计算总和。实际上,对于像[1,2,3,4] 这样的列表,它会导致S = 0+1+1+2+1。所以它需要一些工作。一个问题是,在 prolog 中,=/2 不是 算术赋值语句。要分配算术表达式,请使用is/2
  • 你说得对,我忘了is/2。不过,我认为没有递归是不可能做到的。
  • @Świstak35 实际上,我认为在这种情况下,OP 使用 = 是可以的。我没有注意到 Turbo Prolog 标签。 Turbo Prolog 允许将= 用作is(不知道为什么,但确实如此)。我同意:递归是唯一简单的方法,但是正如您所指出的,可以在尾递归和非尾递归之间进行选择。
  • @Świstak35 在对谓词感到困惑之后,我意识到它不会计算列表的总和(如它第一次出现的那样),而是将列表头部的值添加到其主体的长度.奇怪,那个。

标签: prolog


【解决方案1】:

注意:我用 L is M + N 替换了 L = M + N 形式的命题,因为我没有使用 Turbo Prolog,但我猜其他的一切都会是一样的。

您的f/2 谓词很奇怪。第三个子句只计算列表的长度,但 第二个将 S1 与列表的尾部相关联,并将为 S1 确定的值添加到头部的值 if 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 的条件。如果成功,我们剪切,所以它不会回溯也可以给我们列表的长度。否则我们只会得到列表的长度。

【讨论】:

    猜你喜欢
    • 2020-05-28
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 2017-06-16
    • 2017-01-31
    • 2021-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多