【问题标题】:Sum of a list in prologprolog中列表的总和
【发布时间】:2012-03-14 18:46:20
【问题描述】:

我正在阅读“序言的艺术”一书,我发现了一个练习,上面写着“定义关系 sum(ListOfIntegers,Sum) 如果 Sum 是 ListOfIntegers 的总和,则不使用任何辅助谓词”。I想出了这个解决方案:

sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).

这并不能完全按照我的意愿工作。

?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.

我期待 X 是

s(s(s(s(s(s(0))))))

我认为问题在于我必须在第一次“迭代”中将 Sum 初始化为 0,但这将是非常程序化的,不幸的是我不太适合在 prolog 中完成这项工作。 有什么想法或建议吗?

【问题讨论】:

    标签: prolog successor-arithmetics


    【解决方案1】:

    你的第一个子句应该是

    sum([], 0).
    

    随着这种变化,空洞的true return 消失了,你就会遇到一个问题:第三个子句颠倒了求和的逻辑。应该是

    sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
    

    因为 sum/2 的左侧参数中的 s/1 项的数量应该等于右侧参数中的数量。

    【讨论】:

    • 太棒了!感谢您的帮助!
    【解决方案2】:

    定位问题的最佳方法是首先简化您的查询:

    ?- sum([0],S).
    
    true
    ?- sum([],S).
    
    true
    

    即使对于那些,您也会得到 any S 的答案。喜欢

    ?- sum([],s(s(0))).
    yes
    

    由于[] 只能由您的事实处理,因此该事实必须存在错误。 你说:

    sum([], Sum).
    

    这意味着[] 的总和就是任何东西。你的意思可能是 0。

    另一个错误隐藏在最后一条规则中...修复第一个错误后,我们得到

    ?- sum([0],Sum).
    Sum = 0
    ?- sum([s(0)],Sum).
    no
    

    这里,最后一个子句负责。上面写着:

    sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
    

    递归规则在 Prolog 中相对难以阅读。理解它们的最简单方法是查看:- 并意识到这应该是一个箭头←(因此是从右到左的箭头)含义:

    如果右侧的目标是真实的
    我们得出左侧的结论

    因此,与非正式写作相比,箭头指向相反的方向!

    对于我们的查询,我们可以考虑将Xs 替换为[] 并将X 替换为0。

    sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
    

    所以这条规则现在从右到左读作:如果sum([0],s(Sum)) 为真,... 但是,我们确实知道只有sum([0],0) 成立,但不是那个目标。因此,这条规则永远不适用!你的意图恰恰相反:

    sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
    

    【讨论】:

    • 我从没想过我可以这样解决我的问题...谢谢!
    • 这不是第一个从另一种语言中获得灵感的 Prolog 问题。我猜 Erlang 最近宠坏了 Prolog 程序员,或者它反映了某种规则思维。在 Erlang 中,没有 Peano 也可以: sum([]) -> 0;总和([X|Y])-> X+总和(Y)。并且左右声明式读法模糊,'->'逻辑混乱。
    • Prolog II 确实有 -> 代替 :- 这是大约 1980 年。目的是强调重写方面。 Erlang 大约是 1987 年。
    【解决方案3】:

    我并没有真正遵循你的逻辑,所有看似无关的 s(X) 结构都在浮动。

    做这样的事情不是更容易更简单吗?

    首先,用简单的英语定义您的解决方案,因此:

    • 空列表之和为 0。
    • 非空列表的总和是通过将列表的头部与列表尾部的总和相加得到的。

    根据该定义,序言直接如下:

    sum( []     , 0 ) .  % the sum of an empty list is 0.
    sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
      sum( Xs , T1 ) ,   % - first computing the sum of the tail
      T is X + T1        % - and then, adding that the to head of the list
      .                  % Easy!
    

    【讨论】:

    • OP 正在学习 Prolog 与“Prolog 的艺术”,仍然是一个很好的选择。在那里,一开始使用了 s(X)-自然数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 2013-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多