Prolog:满足目标的变量实例化

Prolog:满足目标的变量实例化,prolog,variable-assignment,Prolog,Variable Assignment,当阅读Mellish的Clocksin在Prolog(2003)中的编程时,出现了一个问题 假设我们使用列表从一个句子映射到另一个句子 change(keith, he). change(very, too). change(X, X). alter([], []). alter([H|T], [X|Y]) :- change(H, X), alter(T, Y). 有人能解释一下变量是如何实例化的吗?我的书对此没有特别深入 例如,使用跟踪时: Call: (7) alter([keith

当阅读Mellish的Clocksin在Prolog(2003)中的编程时,出现了一个问题

假设我们使用列表从一个句子映射到另一个句子

change(keith, he).
change(very, too).
change(X, X).

alter([], []). 
alter([H|T], [X|Y]) :- change(H, X), alter(T, Y).
有人能解释一下变量是如何实例化的吗?我的书对此没有特别深入

例如,使用跟踪时:

Call: (7) alter([keith, is, very, cool], _G2676) ? creep
Call: (8) change(keith, _G2756) ? creep
Exit: (8) change(keith, he) ? creep
Call: (8) alter([is, very, cool], _G2757) ? creep
Call: (9) change(is, _G2759) ? creep
Exit: (9) change(is, is) ? creep
Call: (9) alter([very, cool], _G2760) ? creep
Call: (10) change(very, _G2762) ? creep
Exit: (10) change(very, too) ? creep
Call: (10) alter([cool], _G2763) ? creep
Call: (11) change(cool, _G2765) ? creep
Exit: (11) change(cool, cool) ? creep
Call: (11) alter([], _G2766) ? creep
Exit: (11) alter([], []) ? creep
Exit: (10) alter([cool], [cool]) ? creep
Exit: (9) alter([very, cool], [too, cool]) ? creep
Exit: (8) alter([is, very, cool], [is, too, cool]) ? creep
Exit: (7) alter([keith, is, very, cool], [he, is, too, cool]) ? creep
B = [he, is, too, cool] .
我看到几个内存地址引用打开,如在规则中遇到alter时,并递归配对为:

alter([is, very, cool], ???? tail of Z

看起来新的Y会取Z的尾部的值,但是既然Z只是内存中某个点的引用,那么在返回之前这些变量是如何赋值的呢?这种混淆的另一个原因是,我无法清楚地说明alter谓词中尾部的头部X中的值是如何“构建”的,因为它在哪里保留了change谓词中的新值

阅读此跟踪时,您带来了许多程序性想法(“行李”)。让我们试着用序言的眼光来阅读:

Call: (7) alter([keith, is, very, cool], _G2676) ? creep
序言只是在这里重申你的目标。您可以忽略生成的变量
\u G2676
中的数字;它不是一个内存位置,生成这些变量名的方法因实现和平台而异,Prolog中没有读取任意内存位置的机制,并且这些生成的变量号几乎在任何意义上都是不可访问的。这只是内部记账的事情

您可能发出了如下查询:

?- alter([keith, is, very, cool], B).
这样想吧。你问Prolog,“证明
alter([keith,is,very,cool],B)
并告诉我B是什么。”所以它将尝试这样做

Call: (8) change(keith, _G2756) ? creep
这里发生了什么事?Prolog查看了您的查询,发现您正在使用
alter/2
。它将
alter/2
的头部替换为
alter/2
的主体。快速序言解剖课:

alter([H|T], [X|Y]) :- change(H, X), alter(T, Y).
-------------------    --------------------------
   "the head"                  "the body" 
因此,Prolog说,“为了证明
alter([keith,is,very,cool],B)
我必须用
[keith,is,very,cool]
证明
alter([H | T],[X | Y])
来证明
alter([H | T],[X | Y])
(Prolog以合理的方式管理这些变量名)。因此,现在Prolog用
change(H,X)替换活动查询(T,Y)
。除了,
[H | T]
=
[keith |[is,very,cool]]
B
=
[X | Y]
。因此,在跟踪中打印的内容是:

Call: (8) change(keith, _G2756) ? creep
现在,Prolog必须查看它的
change/2
的第一个子句,找到
change(keith,he)

Exit: (8) change(keith, he) ? creep
Prolog现在说,“好的,我只需要通过查看
alter/2
主体中的下一步来完成我一秒钟前开始的查询,即:

Call: (8) alter([is, very, cool], _G2757) ? creep
就像以前一样,Prolog现在将用
alter/2
的主体替换
alter/2
查询,并尝试实现它,这意味着它现在必须证明:

Call: (9) change(is, _G2759) ? creep
这个更有趣,因为
change/2
的第一个子句不匹配。Prolog无法将
keith
is
统一起来,因此它失败并转到第二个子句。它无法将
is
very
统一起来,因此它转到第三个子句并将
is
与自身统一起来:

Exit: (9) change(is, is) ? creep
这个过程重复进行,处理very/too和cool/cool,然后Prolog运行完列表的组成部分,然后输入基本的
alter/2

Call: (11) alter([], _G2766) ? creep
Exit: (11) alter([], []) ? creep
如果您正在注意,您应该注意到,带有匿名变量的查询行以
Call:
开头,表示Prolog正在更改问题,当Prolog回答问题时,该行以
Exit:
开头。行的开头可以告诉您有关Prolog exe的其他信息执行模型:
重试:
失败:
。但是这里没有这些模型,因为您的查询在第一次尝试时实际上是有效的

从这里开始,您只需退出,因为一切都已成功统一,Prolog基本完成。但这就是“构建”的地方:

Exit: (11) alter([], []) ? creep
Exit: (10) alter([cool], [cool]) ? creep
Exit: (9) alter([very, cool], [too, cool]) ? creep
Exit: (8) alter([is, very, cool], [is, too, cool]) ? creep
Exit: (7) alter([keith, is, very, cool], [he, is, too, cool]) ? creep
这里发生的事情是,
alter([],[])
被证明是正确的,因此它返回到外部调用(注意那里的数字;它们告诉您关于调用堆栈的情况),这意味着Prolog现在已经证明
alter([cool],[cool])
是正确的,这意味着它已经证明了
alter([very,cool],[tool,cool]))
为true,依此类推。这只是尾部递归的工作方式。最后它输出您的查询成功:

B = [he, is, too, cool] .
所以,正如你所说,这里实际上没有内存地址被打开

看起来新的Y会取Z的尾部的值,但是既然Z只是内存中某个点的引用,那么在返回之前这些变量是如何赋值的呢

以“正常”的方式在编程语言中,您使用一些值调用函数,然后返回一个值作为返回值。Prolog不是一种普通的编程语言;您不是在定义函数,而是在定义关系。关系比函数约束少:有时参数是输入,有时是输出。Prolog中的变量它们不是“记忆中的点的引用”。它们只是数据的名称;它们可以是地面的,也可以是自由的,这取决于它们是否被发现

Prolog中的每一步求值,Prolog都在搜索自由变量的绑定。这称为统一,是Prolog中的基本执行模型。当您发出类似
change(keith,X)
的查询时,您要求Prolog证明
change(keith,X)
是真的,并为您提供使其成为真的值X。Prolog将查看该值并返回
true,X=he
。但您也可以要求它
更改(X,he)
并且Prolog将查看它并说,
为真,X=keith
。这是使其成为关系而不是函数的一部分。您也可以说
更改(