【问题标题】:Prolog list elements editingProlog列表元素编辑
【发布时间】:2014-12-08 17:32:08
【问题描述】:

我需要编写一个谓词,它将接受一个数字列表和一个数字 X,然后从这个列表中的 X 个元素(从第一个元素开始)减去 1。 这可能看起来很简单,但我是这种语言的新手,我无法正确编写它。

这是我现在得到的:

sub([H|T], X):-NEWH is H-1, NEWX is X-1, sub(T, NEWX).

但是我怎样才能结束这个递归呢?像这样?

sub([H|T], 0).

当X大于列表元素个数时如何避免出错?

【问题讨论】:

    标签: list recursion prolog predicate subtraction


    【解决方案1】:

    你需要做四件事:

    • 为结果添加一个参数 - 您的规则会生成一个新列表,那里需要一个额外的参数。
    • X 为零时添加一个基本情况 - 你的sub([H|T], 0). 可以进一步简化为sub(_, 0). 为了确保你接受否定的X,你甚至可以使它成为sub(_,X) :- X =< 0.
    • 为列表为空时添加另一个基本情况 - 这可以让您处理X 太大的情况:sub([], _).
    • 确保当X 为零时递归子句不适用 - 您只需在递归子句中添加检查X > 0

    生成的规则如下所示:

    sub(L,X,L) :- X =< 0.
    sub([], _,[]).
    sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWX is X-1, sub(T, NEWX, NEWT).
    

    Demo.

    我想从列表中删除零

    您需要为此添加另一个子句:

    sub(L,X,L) :- X =< 0.
    sub([], _,[]).
    sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWH > 0, NEWX is X-1, sub(T, NEWX, NEWT).
    sub([H|T], X, NEWT) :- X > 0, NEWH is H-1, NEWH =< 0, NEWX is X-1, sub(T, NEWX, NEWT).
    

    Demo.

    【讨论】:

    • 非常感谢!还有一个问题 - 如果减去 1 后的元素等于 0,那么我想将它从列表中删除。我应该在哪里添加代码?
    • @veronicaxoxo 如果要从列表中删除零,请添加一个类似于递归子句的单独子句。请看一下编辑。
    • 谢谢,但它不应该返回 [5,6,8,9] 而不是 [[5,6,7,8,9]]? link
    • @veronicaxoxo 你说得对,我应该删除 NEWT 周围的方括号。
    • 顺便说一句:在你的ideone链接中你写:- goal_to_be_executed.应该是:- initialization(goal_to_be_executed).
    【解决方案2】:

    Prolog 是声明性的。这意味着一旦创建了一个对象,就不能对其进行修改(对于大多数 Prolog 系统来说,严格来说并非如此,但在许多情况下执行这种黑客攻击是不明智的)。

    因此,您需要一个谓词,它将第一个列表作为输入,并生成一个新列表。对于您的示例,例如:

    sub([],_,[]). %base case: you reached the end of the list, return an empty list as well
    sub(L,0,L).   %base case: you reached zero, no more editing, return the list.
    sub([H|T],X,[NewH|newT]) :- %recursive case, subtract one from the head and from X and perform recursion.
        NewH is H-1,
        NewX is X-1,
        sub(T,NewX,newT).
    

    注意有两种基本情况:

    • sub([],_,[]):你到了列表的末尾,可能X 还没有达到零。然后也返回一个空列表。
    • sub(L,0,L)X 达到零,然后您停止编辑并返回列表 L 未更改。

    【讨论】:

      【解决方案3】:

      1) 您的代码不会做任何事情,因为您的 NEWH 不会在任何地方返回。
      2) 你的代码应该返回完整的列表和修改过的元素,所以你的递归应该通过以下方式停止:
      a) 将 X 与零进行比较并附加列表的其余部分

      b) 循环到列表末尾,每次都将 X 与 0 进行比较。

      第一种方法很简单:

      sub(L, 0, L).
      sub([H|T], X, [H1 | Res]) :- 
          H1 is H-1,
          X1 is X-1,
          sub(T, X1, Res).
      

      然后调用:

      >>> sub([1,2,3,4,5,6,7], 4, L).
      L = [0, 1, 2, 3, 5, 6, 7]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-16
        • 1970-01-01
        • 1970-01-01
        • 2018-11-05
        相关资源
        最近更新 更多