这个通配符在这个prolog场景中做什么?

这个通配符在这个prolog场景中做什么?,prolog,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)是

我遇到了以下代码:

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)是如何工作的?它如何知道要检查哪些值以及如何知道它检查了所有可能的值

编辑:我想我理解为什么这样做,但我希望有人能帮我验证一下:
当我使用通配符“调用”connectRow时,它将通配符与connectRow谓词中的“R”匹配。可能是这样吗?

这个
\u
和其他变量一样,只是你看到的每个变量都被视为一个不同的变量,Prolog不会告诉你它与什么相结合。那里没有什么特别的行为;如果它让你对行为感到困惑,只需发明一个全新的变量,并把它放在那里,看看它能做什么

让我们谈谈Prolog如何处理变量。这里有一个实验,你可以跟着做,如果你碰巧有一些无用的先入之见,它会破坏这些先入之见

?- length([2,17,4], X)
X = 3.
很多Prolog都是这样的,很容易陷入这样的思维陷阱:有指定的“out”变量像返回值一样工作,有指定的“in”变量像参数一样工作。毕竟:

?- length([2,17,4], 3).
true.

?- length([2,17,4], 5).
false.
在这里,我们开始看到一些有趣的事情正在发生。一个错误的直觉是Prolog不知何故跟踪输入和输出变量,并在这种情况下进行“检查”。但事实并非如此,因为统一比这更普遍。注意:

?- length(X, 3).
X = [_G2184, _G2187, _G2190].
现在我们将传统的参数/返回值颠倒过来:Prolog知道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).
这说明无论X和Y如何,
connectRow(X,Y,0)
都是正确的。这是基本情况

connectRow([spot(_, R, _, _)|Spots], R, K) :-
此规则匹配特定结构的点列表,假定第一个点的第二个值(R)与第二个参数匹配

K1 is K-1, connectRow(Spots, R, K1).
该子句的主体基本上是在递减第三个参数K时重复出现的

K1 is K-1, connectRow(Spots, R, K1).
现在很清楚,这基本上会生成一个列表,看起来像
[spot(u,R,u,u,u,u,u),…spot(u,R,,,u)]
的长度为K的列表,在
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
所以这里似乎有一些bug;如果我确信这就是整个故事,我会说:

  • 基本情况应该使用空列表,而不是匹配任何内容
  • 在归纳的情况下,我们应该规定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位于
结构中,但在其他位置,例如
\u G918
中,会出现外观怪异的自动生成变量。碰巧的是,我们可以使用
\uu
而不是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 
所有这些看起来奇怪的变量都存在,因为我们使用了
\uu
。请注意,所有的
spot
结构在第二个位置都有完全相同的生成变量,因为Prolog被告知必须将
connectRow
的第二个参数与
spot
的第二个位置统一起来。到处都是这样,因为R被递归地“传递”到下一个对connectRow的调用

希望这有助于解释您的示例中的
\uuu
以及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=
没有什么特别的;它统一了表达式的两侧,但两侧都可以是表达式而不是变量:

?- 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匹配?是的,它将
\uu
R
统一起来。但是unifi