Prolog 递归中的回溯如何不导致无限循环?

Prolog 递归中的回溯如何不导致无限循环?,prolog,Prolog,假设member/2谓词定义为: member(X,[X|R]). member(X,[Y|R]) :- member(X,R). 我的问题是: member(X, [1, 2, 3]). 一旦prolog将X与1统一起来,如果我键入,prolog如何获得其他可能的统一? 难道不可以先从序言中回溯,然后从上到下重新读取包含成员定义的文件,并再次计算member(X[X | R])。这会再次将X与1统一起来吗?您所述的规则是: 成员(X[X|R])。 “管道”操作符将列表的第一个元素与列表的其

假设member/2谓词定义为:

member(X,[X|R]).
member(X,[Y|R]) :- member(X,R).
我的问题是:

member(X, [1, 2, 3]).
一旦prolog将X与1统一起来,如果我键入
,prolog如何获得其他可能的统一
难道不可以先从序言中回溯,然后从上到下重新读取包含成员定义的文件,并再次计算
member(X[X | R])。
这会再次将X与1统一起来吗?

您所述的规则是:

  • 成员(X[X|R])。
  • “管道”操作符将列表的第一个元素与列表的其余元素分开。所以,如果列表是
    [1,2,3]
    X=1
    ,和
    R=[2,3]
    X
    [X | R]
    列表(即第一个成员)的
    car

    因此,在本例中,
    成员(1[1,2,3])。
    true

  • 成员(X[Y | R]):-成员(X,R)。

  • 第二种情况涉及列表的第一个成员与X不同的情况。如果是这样,则调用
    成员(X,R)
    ,并检查列表的
    cdr
    (即从第二个元素开始)

    因此,
    成员(1[1,2,3])。
    不会触发递归


    例如,当元素不在列表中时会发生什么

    为简洁起见,
    成员(1,[2])。
    true
    还是
    false

    这属于第二条规则,因为
    X=1
    不同于
    Y=2

    但是,列表的
    cdr
    是一个空列表(即,在第一个元素旁边没有任何元素)

    所以
    member(1,[2]):-member(1,[])。
    ,而这个
    member(1,[])
    求值总是
    false。


    Prolog的输出:

    ~ $ swipl
    SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
    Please run ?- license. for legal details.
    
    For online help and background, visit http://www.swi-prolog.org
    For built-in help, use ?- help(Topic). or ?- apropos(Word).
    
    ?- [user].
    |: member(X, [X | L]) :- write('Evaluated first clause with X='), write(X), write('.'), nl.
    |: member(X, [Y | L]) :- write('Evaluated second clause with X='), write(X), write(' and Y='), write(Y), write('.'), nl, member(X, L).
    |: end_of_file.
    % user://1 compiled 0.01 sec, 2 clauses
    true.
    
    ?- member(1, [1, 2, 3]).
    Evaluated first clause with X=1.
    true .
    
    ?- member(2, [1, 2, 3]).
    Evaluated second clause with X=2 and Y=1.
    Evaluated first clause with X=2.
    true .
    
    ?- member(4, [1, 2, 3]).
    Evaluated second clause with X=4 and Y=1.
    Evaluated second clause with X=4 and Y=2.
    Evaluated second clause with X=4 and Y=3.
    false.
    
    ?- X=1, member(X, [1, 2, 3]).
    Evaluated first clause with X=1.
    X = 1 .
    
    (省略警告)。

    这个怎么样

    注意以下几点:

    • 程序被读取一次,然后留在内存中,等待用户输入查询(与数据库场景相同)
    • 当它执行时,它会在内存中构建一个“搜索树”
      • 遇到的每个谓词的OR节点:任何分支(对应于该谓词的子句)都必须为TRUE
      • 遇到的每个子句体都有一个AND节点:所有分支(与
        分隔的子句体中的调用相对应)都必须为TRUE
    • 当程序可以“在树的底部退出”并且
      • 在任何AND节点下,所有分支都为TRUE
      • 在任何OR节点下,至少有一个分支为TRUE(在Prolog中,OR节点下只有一个“活动分支”)
    • 如果找不到这样的树,程序最终会失败(这可能需要一些时间)
    • 程序成功后,树将保持活动状态,以防用户要求“更多解决方案”
    • 如果您要求“更多解决方案”,将在底部重新输入树,并尝试其他分支
    以及:

    • 变量名是子句的局部变量
    • 变量内容(如果他们说“变量未绑定”,则为术语或没有内容的单元格)始终是全局的。如果树中较深的节点“细化”其变量之一的内容,则此更改在树的最顶端节点可见(尽管是在另一名称或另一术语的一部分下)

    “第二种情况涉及列表中第一个成员与X不同的情况”-不,不是这样。它不关心统一第一个元素。第二种情况只是忽略第一个元素,使其能够递归调用列表其余部分的谓词。您可以在swi prolog上进行测试。链式规则是。仅第二条规则是不够的。我还觉得调用cdr
    null
    也是错误的。Prolog要么统一,要么不统一,因此
    [X]
    不能与
    [\u124; Y]
    统一,因为Prolog希望
    Y
    是一个非空列表。这不是真的。它不包括第一个元素与
    X
    不同的情况。它根本不关心
    X
    的值是多少。您应该使用文件的
    end\u,而不是使用^D(Ctrl-D)。
    ()