如何在prolog中写出更早的陈述?

时间:2016-12-21 19:42:49

标签: prolog

我正在看prolog progrm并且无法理解以下

earlier(X, _, [X|_]).
earlier(_, Y, [Y|_]) :- !, fail.
earlier(X, Y, [_|T]) :- earlier(X, Y, T). 

任何人都可以解释它是什么意思吗?

1 个答案:

答案 0 :(得分:0)

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

?- 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.