Prolog prob with" list"不知道为什么

时间:2018-04-09 10:43:52

标签: prolog

我现在有另一个问题

communs(piece(C1, F1, T1, Co1),piece(C2, F2, T2, Co2)) :- 
    C1 = C2;
    F1 = F2;
    T1 = T2;
    Co1 = Co2.

line((A,_),(A_,_)) :-
    A_ = A.

row((_,A),(_,A_)) :-
    A_ = A.

win_line([]).
win_line([(_,_),_]).
win_line([(A,P)|[(A_,P_)|Reste]]):-
    line(A,A_),
    communs(P,P_),
    win_line(Reste).

我真的想做点什么,但我现在不怎么做: 我想得到一个只有同一行坐标的列表,例如(1,1),(1,2),(1,3),

我尝试了这个,但我不认为这是正确的:

selct_line([],[]).
select_line([(A,P)|[(A_,P_)|Reste]], _):-
    line(A,A_),
    select_line(Reste,[(A,P)|[(A_,P_)]).

1 个答案:

答案 0 :(得分:0)

你已经找到了几乎所有的问题,干得好!但是还有很多事情需要注意:

首先,使用AA_作为不同变量的名称是有效的,但非常异常且非常难以阅读。例如,使用A1A2会更好。

其次,你对语法感到困惑。考虑:

?- List = [(A1,P1)|[(A2,P2)|Reste]].
List = [ (A1, P1), (A2, P2)|Reste].

您和您的读者都可以使用第二种更常用的语法。两者都描述了相同的术语,但第二个更清楚地表明您有一个列表,该列表以两对(A1, P1)(A2, P2)开头,后跟一些列表Reste

第三,让我们看看Prolog为您的定义生成的解决方案:

?- win_line(Line), length(Line, Length).
Line = [],
Length = 0 ;
Line = [ (_G983, _G984), _G986],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006))],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), (_G1011, _G1012), _G1014],
Length = 4 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1020, _G1021), piece(_G1026, _G1027, _G1028, _G1029)), ((_G1020, _G1024), piece(_G1026, _G1032, _G1033, _G1034))],
Length = 4 ;

等。生成的所有列表都是均匀的!大概你也想接受长度为1,3,5等的列表?

win_line/1的第二个条款特别奇怪且未明确:

win_line([(_,_),_]).

即使忽略这对坐标,这也可以让我们证明这样的事情:

?- win_line([_, hello_world]).
true .

这不应该是坐标对和piece项的吗?也就是说,你可能想要更像这样的东西:

win_line([((_,_),_)]).

其行为如下:

?- win_line([(0,1), hello_world]).
false.

?- win_line([((0,1), hello_world)]).
true .

但更好:

win_line([((_,_), piece(_,_,_,_))]).

给出:

?- win_line([((0,1), hello_world)]).
false.

?- win_line([((0,1), piece(a,b,c,d))]).
true .

有了这个,结果的列举更有意义:

?- win_line(Line), length(Line, Length).
Line = [],
Length = 0 ;
Line = [ ((_G986, _G987), piece(_G989, _G990, _G991, _G992))],
Length = 1 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006))],
Length = 2 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1014, _G1015), piece(_G1017, _G1018, _G1019, _G1020))],
Length = 3 ;
Line = [ ((_G992, _G993), piece(_G998, _G999, _G1000, _G1001)), ((_G992, _G996), piece(_G998, _G1004, _G1005, _G1006)), ((_G1020, _G1021), piece(_G1026, _G1027, _G1028, _G1029)), ((_G1020, _G1024), piece(_G1026, _G1032, _G1033, _G1034))],
Length = 4 .

第四,现在的行为如下:

?- win_line([((0,0), piece(a,b,c,d)), ((0,1), piece(a,b,c,d)), ((1,1), piece(now, something, completely, different))]).
true .

您强制执行列表的前两个元素之间的关系,但不强制执行第二个和第三个元素之间的关系。这是因为对于此表单的列表,您在前两个元素上调用communs,但在第二个和第三个元素上调用 not

检查Prolog中每对相邻元素的常用方法是遵循以下模式:

valid_list([]).
valid_list([_]).
valid_list([A, B | Rest]) :-
    valid_pair(A, B),
    valid_list([B | Rest]).

也就是说,元素B被传递回递归调用。因此,如果您在表单[A, B, C]的列表中调用此列表,则会同时调用valid(A, B)valid(B, C)。您的代码只检查第一个而不是第二个,因此它接受无效列表。

最后,((0,1), piece(...))形式的这些术语在所有括号中都难以阅读。最好使用像move(0, 1, piece(...))这样的格式。这会让你更加困惑,因为你对win_line的第二个句子感到困惑。

相关问题