【问题标题】:Prolog members of listsProlog 列表成员
【发布时间】:2014-05-05 23:31:44
【问题描述】:

Prolog 新手在这里,如果我想知道某些东西是否是列表的成员,他们想知道为什么这些规则不能独立存在。

member(X, [X|_]).

member(X, [_|Y]) :- member(X,Y).

如果我要求以下规则:

member(will, [anna, eddie, pat, will, marjorie, donna]).

我是真的,但是如果我删除:

member(X, [X|_]).

只要离开第二条规则,我就错了。如果第二条规则声明“如果 X 是列表尾部的成员,则 X 是列表的成员”,为什么会这样?

“will”是该列表尾部的成员。

而且,为什么可以

member(X, [X|_]).

单独告诉我 X 何时是列表的头部(当第二条规则不能时)?

谢谢。

【问题讨论】:

  • 如果第一个子句member(X, [X|_]). 不存在,问自己一个问题,“第二个子句中的member(X, Y) 什么时候会变为真(成功)?”。请记住:这是一个递归查询。
  • 考虑memberd/2,它基本相同,但没有多余的答案。

标签: prolog


【解决方案1】:

如果您只有member(X, [X|_]). 并且执行此查询:member(will, [will,anna]).

你会得到true.,因为根据你的规则,X,即 will,是列表的头部。

但是如果你只有那个规则并且你执行member(anna, [will,anna]).,你会得到错误,因为安娜不是你列表的头。

让我们看看你的第二条规则。

您将程序创建为member(X, [_|Y]) :- member(X,Y).

你执行查询member(will, [anna, eddie, pat, will, marjorie, donna]).

这就是 Prolog 看到的:

取出列表并移除头部。对列表的其余部分执行相同的操作,直到尾部为空。

你得到false.,因为你的列表中没有任何元素了。

您的问题是您没有检查 X 是否是您列表中的成员。您也可以将该规则重命名为 removehead(X,[_|Y]):-removehead(X,Y).

【讨论】:

    【解决方案2】:

    只要离开第二条规则,我就错了。

    没有基本情况的规则失败的原因是,当列表下降到单个项目时,当列表变为空时,没有规则可以与其右侧统一。

    您可以使用较短的列表在一张纸上播放:

    • member(will, [anna, will])开头。
    • 这与规则统一,将anna统一为_,并将[will]保持在Y
    • 这再次与规则统一,将will统一为_并将[]保持在Y
    • 现在 Prolog 尝试 member(will, []) 规则不再与它统一,因为 member(X, [_|Y]) 要求第二个参数是至少包含一项的列表。
    • 一旦最后一次统一失败,失败就会向上传播,导致将 false 返回给顶部调用者。

    而且,为什么member(X, [X|_]). 可以单独告诉我 X 何时是列表的首位

    这是因为规则立即成功,无需与右边的任何其他规则统一。

    一般来说,当你处理数据结构的递归处理时,你需要寻找两件事:

    • 基本情况,它告诉在最简单的情况下或递归数据结构何时简化为退化情况(例如空列表、单节点“叶”树和等等)。
    • 归约步骤,说明如何使问题更接近基本情况。

    单独处理基本情况有时会给您带来结果;单独处理还原步骤永远不会给您正确的结果,因为它所做的所有还原工作都是徒劳的。

    【讨论】:

    • 您的答案“没有基本情况的规则失败的原因是,当列表缩小到单个项目时,没有与之统一的规则”是不正确的。单个项目列表确实与规则头统一。
    • @PauloMoura 对不起,我不清楚这一点 - 我的意思是当进入规则的列表有一个项目时,注意与规则的右侧统一。我编辑了答案以澄清。谢谢!
    【解决方案3】:

    member(X, [_|Y]) (1) 仅匹配 [_|Y] 形式的列表,并且 (2) 从不查看实际元素。尝试跟踪执行:

    ?- trace.
    true.
    
    [trace]  ?- member(foo, [foo, bar]).
       Call: (6) member(foo, [foo, bar]) ? creep
       Call: (7) member(foo, [bar]) ? creep
       Call: (8) member(foo, []) ? creep
       Fail: (8) member(foo, []) ? creep
       Fail: (7) member(foo, [bar]) ? creep
       Fail: (6) member(foo, [foo, bar]) ? creep
    false.
    

    正如预期的那样,您的 member 版本只是跳过元素,因为它只想查看尾部,直到遇到与头部模式不匹配的 []

    另一个版本,member(X, [X|_]) 可以匹配头部每个定义。它会查看头部并将其与您要查找的项目统一起来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多