Prolog 序言中的感叹号

Prolog 序言中的感叹号,prolog,Prolog,鉴于以下事实和谓词: sound(time1). sound(time2). sun(time3). relax(X):-sound(X),!,sun(X). relax(_):-sun(_). 执行放松时。由于的原因,我希望得到S=time1,表示(如果我错了请纠正我),如果“X”满意,则停止回溯 以下是跟踪: 3 ?- trace. true. [trace] 3 ?- relax(S). Call: (6) relax(_G1831) ? creep Call: (7) s

鉴于以下事实和谓词:

sound(time1).
sound(time2).
sun(time3).
relax(X):-sound(X),!,sun(X).
relax(_):-sun(_).
执行
放松时。
由于
的原因,我希望得到
S=time1
,表示(如果我错了请纠正我),如果“X”满意,则停止回溯

以下是跟踪:

3 ?- trace.
true.

[trace] 3 ?- relax(S).
   Call: (6) relax(_G1831) ? creep
   Call: (7) sound(_G1831) ? creep
   Exit: (7) sound(time1) ? creep
   Call: (7) sun(time1) ? creep
   Fail: (7) sun(time1) ? creep
   Fail: (6) relax(_G1831) ? creep
false.

那么为什么Prolog还要检查
sun(time1)
,即使它在被
sound(X)
满足后遇到了感叹号(因为
sound(time1)
是事实)

它仍将尝试满足规则的其余部分,只是不会回溯到感叹号之前。也就是说,如果
sun(X)
失败,它将不会回溯并尝试将不同的对象与
sound(X)
匹配,而是无法完全匹配该规则。

符号防止从右到左的子句回溯,它就像一个单向门,这样它就不会回溯到切口之外

sound(time1)
为true时,将对下一个子句
sun(time1)
进行求值,只有这样prolog才会发现
sun(time1)
false
(通过搜索知识库,它实际上并不知道这是一个事实)

然后,由于剪切,prolog不会在第一个子句中尝试值
time2
time3

有关剪切的更多信息:

Prolog从左到右计算谓词的子句。它将值绑定到最左侧子句中的变量。如果子句为
true
,则它将移动到下一个子句。如果
为false
,prolog还会尝试其他值

如果任何一个子句不能被任何值满足,那么它将是
false
,整个谓词也是如此(因为这些子句由and连接)

整个过程就像树的深度优先遍历,其中子句是节点,边表示其变量的不同值。如果遍历发现一个子句是
false
,它将返回到它前面的子句并尝试一个不同的值


伤口来了。如果在两个子句之间放置一个cut(
),这意味着如果cut之后的子句变为
false
,则仅当计算在cut之后运行时,才会继续尝试新值。这意味着剪切前使用的变量值被锁定,并且当计算穿过剪切时,它们不能更改。

为了进一步澄清这一点,如果有人仍在挣扎感叹号运算符的工作方式(如我所做的),下面是一个示例:

sound(time3).
sound(time1).
sun(time1).
relax(X):-sound(X),!,sun(X).
对于这个特定的示例,如果您向Prolog询问
?-relax(S)。
这将导致false。我们可以这样描述Prolog:

  • Prolog搜索询问谓词(relax(SOMEVARIABLE unifiable 在我们的示例中使用S)
  • Prolog查找谓词relax(X)。变量 X和S现在已绑定
  • Prolog开始评估子句:
    • 声音(X)
      • Prolog在文件中搜索 满足声音(X)
      • 它查找事实声音(time3)。并将其与变量X=S=time3相统一
      • 序言继续到下一个小句,它是运算符!所以他不会回到这个接线员后面
    • 太阳(X)
      • Prolog在文件中搜索满足sun(X)的事实。X已经绑定,因此它搜索未绑定的太阳(time3) 存在
  • 结论
    • 在这一点上,如果没有!操作符Prolog将返回(回溯)到声音(X),并将变量X=S重新分配为X=S=time1。这将最终导致,因为事实太阳(时间1)存在
    • Prolog返回false,因为他无法匹配任何规则的relax
  • 就像我在第四章中说的那样。没有!操作员:它将导致成功

    sound(time3).
    sound(time1).
    sun(time1).
    relax(X):-sound(X),sun(X).
    

    如果我在某一点上错了,请随时纠正我。

    这与函数式编程无关,也不适用于编程语言标签。。。不要仅仅因为喜欢就添加标签。所以你的意思是,
    relax(X):-sound(X),!,太阳(X)。
    放松(X):-声音(X),太阳(X)?prolog将只尝试当前的“X”,然后失败@罗恩:当然,这两者之间有区别,那就是切割的位置。如果
    sun(X)
    可以多次求解,则第一个版本可能会多次给出答案-例如,如果您将
    sun(time1)。
    sun(X):-sound(X)。
    添加到谓词中,然后请求
    relax(S)
    。第二个版本将始终得到一个(或否)答案。您是正确的,但是它不会对您当前的谓词集产生影响。@l4mpi:好的,这就是奇怪的部分:为什么prolog检查超出
    在<代码>放松(X):-声音(X),!,太阳(X)。
    ?如果prolog发现
    relax(time1)
    是一个事实,那么
    不是吗告诉它不要检查任何其他东西,除了不要检查太阳(时间1)
    ?@ron你误解了伤口的作用。它并没有停止计算,只是意味着所有的选择点都会累积到
    将被丢弃。当达到
    声音(X)
    时,可能的解决方案是
    time1
    time2
    。prolog解释器选择第一个(
    time1
    ),并创建一个选择点,如果子句的其余部分失败,它可以回溯到该选择点,因此它可以使用
    time2
    重新计算。
    除了放弃此选择点外,不执行任何操作。Prolog现在计算谓词的其余部分,但不能在
    之前回溯并用
    time2
    进行测试。@ron Prolog可以检查超出切割的部分(从左到右),但不能回溯超出切割的部分(从右到左)-这就是