2013-01-23 26 views
0

我遇到这样的代码:这个通配符在这个prolog场景中做了什么?

connectRow(_,_,0). 
connectRow([spot(_,R,_,_)|Spots],R,K) :- K1 is K-1, connectRow(Spots,R,K1). 

/*c*/ 
connectRows([]). 
connectRows(Spots) :- 
    connectRow(Spots,_,9), 
    skip(Spots,9,Spots1), 
    connectRows(Spots1). 

如何通配符在connectRow(斑点,_,9)工作?它如何知道要检查哪些值以及它如何知道它检查了所有可能的值?

编辑:我想我理解为什么这个工作,但我想如果有人可以验证这个对我来说: 当我用通配符“connect”connectRow它匹配通配符与connectRow中的“R”谓词。这可能吗?

回答

2

_就像任何其他变量,除了你看到的每个变量被视为一个不同的变量,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] ; 

希望这有助于!

+0

我很困惑这是如何工作的。 没有我指定通配符是什么,我不认为它会工作。 它可能是它的工作原理,因为当涉及到connectRow谓词它匹配通配符与R? – Shookie

+0

是的,它将'_'与'R'结合在一起。但是在Prolog中的统一与你的标准参数传递完全不同。 –

+0

感谢您的回复,我现在明白了。当你说不一样/发送链接时,你能扩展你的意思吗? – Shookie