_
就像任何其他变量,除了你看到的每个变量被视为一个不同的变量,Prolog不会告诉你它与什么它统一。那里没有特别的行为;如果它让你对这种行为感到困惑,那么只需创造一个全新的变量,并将它放在那里看看它的作用。
让我们来谈谈Prolog如何处理变量。这里有一个实验,如果你碰巧拥有它们,那么它可能会破坏无用的先入为主的观念。
?- length([2,17,4], X)
X = 3.
很多的Prolog看起来是这样的,很容易陷入思维,有被指定为“出”的作用就像返回值和“中”的作用就像参数变量指定变量的陷阱。毕竟:
?- length([2,17,4], 3).
true.
?- length([2,17,4], 5).
false.
在这里,我们开始看到有趣的事情正在发生。一个错误的直觉是,Prolog会以某种方式跟踪输入和输出变量,并在这种情况下“检查”。但这并不是什么事情,因为统一比这更普遍。注意:
?- length(X, 3).
X = [_G2184, _G2187, _G2190].
现在,我们已经颠覆了传统的参数/返回值:序言知道,X是一个列表三个项目长,但不知道是什么项目实际上是。信不信由你,当你知道你需要多少,但是你不需要单独命名它们时,这种技术经常用于生成变量。
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G2196],
Y = 1 ;
X = [_G2196, _G2199],
Y = 2 ;
X = [_G2196, _G2199, _G2202],
Y = 3
它发生的长度的定义是非常普遍的,Prolog可以用它来生成列表及其长度。这种行为是Prolog非常擅长“生成和测试”解决方案的一部分。您可以从逻辑上定义问题,Prolog应该能够生成逻辑上合理的值以进行测试。
所有这些变化从长度的一个非常简单的定义弹簧:
length([], 0).
length([_|Rest], N1) :-
length(Rest, N0),
succ(N0, N1).
的关键是计算长度像一个过程不读这个,而是把它看作名单和数量之间的逻辑关系。该定义是归纳性的,将空列表与0相关联,列表中的某些项目与1 +列表中其余部分的长度相关。使这项工作的引擎被称为统一。
在第一种情况下,length([2,17,4], X)
,值[17,4]与Rest一起统一,N0与2统一,N1与3统一。该过程是递归的。在最后一种情况下,X与[]和Y统一为0,这自然会导致下一个我们有一些项目并且Y是1的情况,并且表示列表中项目的变量没有任何东西尤其是统一与无关紧要,因为该变量的值从未被使用过。
看着你的问题,我们看到了同样的递归结构。谓词相当复杂,所以让我们把它们分成几部分。
connectRow(_, _, 0).
这是说connectRow(X, Y, 0)
是真实的,不管X和Y这是基本情况。
connectRow([spot(_, R, _, _)|Spots], R, K) :-
此规则相匹配的特定结构的点的列表,假定所述第一点的第二值(R)的第二参数相匹配。
K1 is K-1, connectRow(Spots, R, K1).
本节的主体基本上重复上递减K,第三个参数。
现在很清楚,这基本上会生成一个长度为K = [spot(_, R, _, _), spot(_, R, _, _), ... spot(_, R, _, _)]
的列表,并且spot
的其他三个位置中没有特殊值。事实上,这就是我们测试时看到的:
?- connectRow(X, Y, 0).
true ;
(infinite loop)^CAction (h for help) ? abort
% Execution Aborted
?- connectRow(X, Y, 2).
X = [spot(_G906, Y, _G908, _G909), spot(_G914, Y, _G916, _G917)|_G912] ;
(infinite loop)^CAction (h for help) ? abort
所以这里似乎有一些错误;如果我确信这是故事的全部,我会说:
- 基本情况应该使用空列表,而不是匹配任何
- 我们应该在感性的情况下规定,K> 0
- 我们应该使用
clpfd
如果我们希望能够产生所有的可能性
使我们体验到不同的变化:
:- use_module(library(clpfd)).
connectRow([], _, 0).
connectRow([spot(_, R, _, _)|Spots], R, K) :-
K #> 0, K1 #= K-1, connectRow(Spots, R, K1).
?- connectRow(X, Y, 0).
X = [] ;
false.
?- connectRow(X, Y, 1).
X = [spot(_G906, Y, _G908, _G909)] ;
false.
?- connectRow(X, Y, Z).
X = [],
Z = 0 ;
X = [spot(_G918, Y, _G920, _G921)],
Z = 1 ;
X = [spot(_G918, Y, _G920, _G921), spot(_G1218, Y, _G1220, _G1221)],
Z = 2
您会注意到,在结果中,我们有Y站在我们的spot
结构中,但我们有奇怪的自动生成的变量在其他位置,如_G918
。当它发生时,我们可以使用_
,而不是Y和看到类似的效果:
?- connectRow(X, _, Z).
X = [],
Z = 0 ;
X = [spot(_G1269, _G1184, _G1271, _G1272)],
Z = 1 ;
X = [spot(_G1269, _G1184, _G1271, _G1272), spot(_G1561, _G1184, _G1563, _G1564)],
Z = 2
所有这些奇形怪状的变量都在那里,因为我们使用_
。请注意,所有spot
结构在第二个位置的生成变量完全相同,因为Prolog被告知必须将connectRow
的第二个参数与第二个位置spot
统一。这是无处不在的,因为R是递归地传递给connectRow的下一个调用。
希望这有助于解释您的示例中_
会发生什么情况,以及一般情况下的Prolog统一。
编辑:统一的东西有R
要回答以下你的问题,你可以直接或通过其绑定到一个变量,使用变量统一用R值。例如,我们可以直接将其绑定:
?- connectRow(X, 'Hello, world!', 2).
X = [spot(_G275, 'Hello, world!', _G277, _G278), spot(_G289, 'Hello, world!', _G291, _G292)]
我们也可以绑定,然后后来分配给它:
?- connectRow(X, R, 2), R='Neato'.
X = [spot(_G21, 'Neato', _G23, _G24), spot(_G29, 'Neato', _G31, _G32)],
R = 'Neato'
有什么特别的话R=<foo>
;它统一了表达式的两边,但双方可以是表达式,而不是变量:
?- V = [2,3], [X,Y,Z] = [1|V].
V = [2, 3],
X = 1,
Y = 2,
Z = 3.
所以,你可以在另一个谓语用[R一样好:
?- connectRow(X, R, 2), append([1,2], [3,4], R).
X = [spot(_G33, [1, 2, 3, 4], _G35, _G36), spot(_G41, [1, 2, 3, 4], _G43, _G44)],
R = [1, 2, 3, 4] ;
注意,这对于创造了机会回溯并生成其他解决方案。例如:
?- connectRow(X, R, 2), length(R, _).
X = [spot(_G22, [], _G24, _G25), spot(_G30, [], _G32, _G33)],
R = [] ;
X = [spot(_G22, [_G35], _G24, _G25), spot(_G30, [_G35], _G32, _G33)],
R = [_G35] ;
X = [spot(_G22, [_G35, _G38], _G24, _G25), spot(_G30, [_G35, _G38], _G32, _G33)],
R = [_G35, _G38] ;
希望这有助于!
我很困惑这是如何工作的。 没有我指定通配符是什么,我不认为它会工作。 它可能是它的工作原理,因为当涉及到connectRow谓词它匹配通配符与R? – Shookie
是的,它将'_'与'R'结合在一起。但是在Prolog中的统一与你的标准参数传递完全不同。 –
感谢您的回复,我现在明白了。当你说不一样/发送链接时,你能扩展你的意思吗? – Shookie