2016-12-21 24 views

回答

0

顾名思义,earlier(X, Y, Zs)显然应该检查元素X是否早于列表Zs中的第一个出现Y。它种做到这一点:

?- earlier(a, b, [a, b, c, d]). 
true ; 
false. 

?- earlier(b, d, [a, b, c, d]). 
true ; 
false. 

凭借独特的处理,如果第二个参数是不是在给定列表:

?- earlier(a, not_in_list, [a, b, c, d]). 
true ; 
false. 

这是如何工作的?第一个条款说,如果X是列表的头部,则X出现在列表的前面,而不是任何内容,由匿名变量_表示。第二个条款说,如果Y是列表的头部,则没有任何内容(_在第一个参数位置)在Y之前。在这种情况下,谓词失败并使用剪切来避免发现虚假解。第三个条款只适用于第一个和第二个条款的列表。

由于切,这个定义不是很声明,并为人们所预料的一些有趣的用途不起作用:

?- earlier(X, Y, Zs). 
Zs = [X|_G947] ; 
false. 

?- earlier(a, b, Zs). 
Zs = [a|_G923] ; 
false. 

?- earlier(X, Y, [a, b, c, d]). 
X = a ; 
false. 

最后一种情况,特别是可能对某些使用案例有趣。这里是一个更声明版本:

earlier_than(X, Y, Zs) :- 
    append(InitialPart, [X | _Rest], Zs), 
    notmember_of(Y, InitialPart). 

notmember_of(_X, []). 
notmember_of(X, [Y|Xs]) :- 
    dif(X, Y), 
    notmember_of(X, Xs). 

你可以使用这个更漂亮列举的解决方案:

?- earlier_than(X, Y, Zs). 
Zs = [X|_G947] ; 
Zs = [_G1162, X|_G1166], 
dif(Y, _G1162) ; 
Zs = [_G1254, _G1257, X|_G1261], 
dif(Y, _G1257), 
dif(Y, _G1254) ; 
Zs = [_G1346, _G1349, _G1352, X|_G1356], 
dif(Y, _G1352), 
dif(Y, _G1349), 
dif(Y, _G1346) . 

?- earlier_than(a, b, Zs). 
Zs = [a|_G923] ; 
Zs = [_G1086, a|_G1090], 
dif(_G1086, b) ; 
Zs = [_G1169, _G1172, a|_G1176], 
dif(_G1169, b), 
dif(_G1172, b) ; 
Zs = [_G1252, _G1255, _G1258, a|_G1262], 
dif(_G1252, b), 
dif(_G1255, b), 
dif(_G1258, b) . 

?- earlier_than(X, Y, [a, b, c, d]). 
X = a ; 
X = b, 
dif(Y, a) ; 
X = c, 
dif(Y, b), 
dif(Y, a) ; 
X = d, 
dif(Y, c), 
dif(Y, b), 
dif(Y, a) ; 
false. 

就个人而言,如果规范允许,我会还新增了member(Y, Rest)earlier_than/3定义。这使事情更好:

?- earlier_than(X, Y, Zs). 
Zs = [X, Y|_G950] ; 
Zs = [X, _G949, Y|_G953] ; 
Zs = [X, _G949, _G952, Y|_G956] . 

?- earlier_than(a, b, Zs). 
Zs = [a, b|_G926] ; 
Zs = [a, _G925, b|_G929] ; 
Zs = [a, _G925, _G928, b|_G932] . 

?- earlier_than(X, Y, [a, b, c, d]). 
X = a, 
Y = b ; 
X = a, 
Y = c ; 
X = a, 
Y = d ; 
X = b, 
Y = c ; 
X = b, 
Y = d ; 
X = c, 
Y = d ; 
false. 
+0

谢谢你的解释。 –

+0

如果您对此答案满意,请点击旁边的复选标记以“接受”。 –