if_/3
让我们尝试使用;来解决一个简单的问题。例如,我将尝试将一个列表(按 predicate 排序)p/2
分成两个列表:一个前缀,对于每个元素X
,我们都有.p(X, true)
p/2
p(X, false)
reif
我将像这里一样使用图书馆。所以,这是我的程序的完整代码:
:- use_module(reif).
pred_prefix(Pred_1, List, L_true, L_false) :-
pred_prefix_aux(List, Pred_1, L_true, L_false).
pred_prefix_aux([], _, [], []).
pred_prefix_aux([X|Xs], Pred_1, True, False) :-
if_( call(Pred_1, X),
( True = [X|True0],
pred_prefix_aux(Xs, Pred_1, True0, False)
),
( True = [],
False = [X|Xs]
)
).
传递给此元谓词的谓词将采用两个参数:第一个是当前列表元素,第二个是true
or 或false
。理想情况下,此谓词将始终成功并且不会留下选择点。
在 的第一个参数中if_/2
,谓词使用当前列表元素进行评估;第二个论点是什么时候发生true
;第三个论点是什么时候发生false
。
有了这个,我可以将列表拆分为前导a
和休息:
?- pred_prefix([X, B]>>(=(a, X, B)), [a,a,b], T, F).
T = [a, a],
F = [b].
?- pred_prefix([X, B]>>(=(a, X, B)), [b,c,d], T, F).
T = [],
F = [b, c, d].
?- pred_prefix([X, B]>>(=(a, X, B)), [b,a], T, F).
T = [],
F = [b, a].
?- pred_prefix([X, B]>>(=(a, X, B)), List, T, F).
List = T, T = F, F = [] ;
List = T, T = [a],
F = [] ;
List = T, T = [a, a],
F = [] ;
List = T, T = [a, a, a],
F = [] .
例如,您如何摆脱前导 0:
?- pred_prefix([X, B]>>(=(0, X, B)), [0,0,1,2,0,3], _, F).
F = [1, 2, 0, 3].
当然,这可以写得更简单:
drop_leading_zeros([], []).
drop_leading_zeros([X|Xs], Rest) :-
if_(=(0, X), drop_leading_zeros(Xs, Rest), [X|Xs] = Rest).
在这里,我刚刚删除了所有不必要的参数。
如果您必须在没有 的情况下 if_/3
执行此操作,则必须编写:
drop_leading_zeros_a([], []).
drop_leading_zeros_a([X|Xs], Rest) :-
=(0, X, T),
( T == true -> drop_leading_zeros_a(Xs, Rest)
; T == false -> [X|Xs] = Rest
).
在这里,我们假设在=/3
没有选择点的情况下确实总是会成功,并且T
总是会是true
or false
。
而且,如果我们都没有=/3
,你会写:
drop_leading_zeros_full([], []).
drop_leading_zeros_full([X|Xs], Rest) :-
( X == 0 -> T = true
; X \= 0 -> T = false
; T = true, X = 0
; T = false, dif(0, X)
),
( T == true -> drop_leading_zeros_full(Xs, Rest)
; T == false -> [X|Xs] = Rest
).
这并不理想。但现在至少你可以在一个地方亲眼看到实际发生了什么。
PS:请仔细阅读代码和顶层交互。