【问题标题】:Prolog - transforming to tail recursionProlog - 转换为尾递归
【发布时间】:2021-03-21 02:47:48
【问题描述】:

作为 Prolog 的新手,我了解到尾递归是经过优化的。因此,我正在尝试将以下程序转换为尾递归程序。

sum([], 0).
sum([H|T], N):-
    sum(T, X),
    N is X + H.

这是我尝试过的,很明显我在逻辑上遗漏了一些东西:

sum(List,Sum):-
    sum1(List,0,Sum).

sum1([Element|List],Accumulator,Sum):-
    (NewAccumulator is Accumulator + Element,
    sum1(List,NewAccumulator,Sum);

    List=[] -> Sum = Accumulator
    ).

我的程序中的问题是添加列表中除最后一个之外的所有数字。我该如何改进这个程序?谢谢。

【问题讨论】:

    标签: prolog accumulator


    【解决方案1】:

    问题是你写错了程序。这是正确的:

    sum(List, Sum) :-
        sum_1(List, 0, Sum).
    
    sum_1([], Sum, Sum).
    sum_1([H|T], Sum0, Sum) :-
        Sum1 is Sum0 + H,
        sum_1(T, Sum1, Sum).
    

    但你可以在 stackoverflow 上用谷歌搜索这个版本。

    这也是一个简单的列表折叠:

    sum([H|T], Sum) :-
        foldl(add, T, H, Sum).
    
    add(X, Y, Z) :- Z is X + Y.
    

    【讨论】:

    • 谢谢!但是,请问sum_1([],Sum,Sum).的逻辑是什么?这意味着放入 if else 块并使其成为基本情况有什么区别?
    • @Woden 这就是累加器的工作方式:“当列表为空时,累加器总和”。
    【解决方案2】:

    我同意 TA_intern 的解决方案,但这里有一个补充说明为什么你的程序出错了。

    以下程序尽可能多地保留您的代码,但正确:

    sum(List,Sum):-
        sum1(List,0,Sum).
    
    sum1([Element|List],Accumulator,Sum):-
        NewAccumulator is Accumulator + Element,
        (sum1(List,NewAccumulator,Sum);
        List=[] -> Sum = NewAccumulator
        ).
    

    你有List=[] -> Sum = Accumulator,这意味着如果你的列表尾部是空的,你会选择Accumulator,这是Element之前所有元素的总和。

    保留更多代码的替代方法是:

    sum1([Element|List], Accumulator, Sum) :-
            (   NewAccumulator is Accumulator+Element,
                sum1(List, NewAccumulator, Sum)
            ;   List=[]
            ->  Sum is Accumulator+Element
            ).
    

    不过,我个人更喜欢 TA_intern 的解决方案。

    【讨论】:

    • 请问为什么这个程序不受欢迎?
    • 我并没有说它不好simpliciter,我只是提到了我个人的喜好,这当然会受到习惯做法的影响。对我来说,它比其他解决方案可读性差,我发现使用 OR (; 经常很混乱。-> 的使用也让我感到困惑。我认为就效率而言,两种解决方案基本上都是相当,所以我偏爱的唯一原因真的是可读性。
    • 感谢您的澄清!这对我很有帮助,因为我也在努力提高可读性和效率。
    • 您介意使用标准缩进吗?
    • @false:什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    • 2019-09-14
    相关资源
    最近更新 更多