此实现尝试保留logical-purity,而不将列表项限制为[_,_],例如
@false's answer 确实如此。
我可以看到施加上述限制确实很有意义......我仍然想解除它——并解决更普遍的问题。
以下内容基于if_/3、splitlistIf/3 和具体化谓词marker_truth/2。
marker_truth(M,T) 将M 的“标记”特性具体化为真值T(true 或false)。
is_marker([_,1])。 % 未具体化
marker_truth([_,1],true)。 %具体化:变体#1
marker_truth(Xs,false) :-
差异(Xs,[_,1])。
很简单!让我们在查询中一起尝试splitlistIf/3 和marker_truth/2:
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2, 0],[4,0]],
splitlistIf(marker_truth,Ls,Pss)。
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0] ,[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]]? ; % 好的
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0] ,[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0],
[9,1],[2,0],[ 4,0]]],
prolog:dif([9,1],[_E,1]) ? ; % 坏的
%% 查询中止(省略了其他 6 个错误答案)
天哪!
上面显示的第二个答案肯定不是我们想要的。
显然,splitlistIf/3 应该 在那时拆分 Ls,
随着目标is_marker([9,1]) 成功。它没有。相反,我们得到了一个冻结的dif/2 目标的答案,该目标将永远被唤醒,因为它正在等待匿名变量_E 的实例化。
猜猜是谁的错! marker_truth/2的第二个子句:
marker_truth(Xs,false) :-
dif(Xs,[_,1])。 % 坏的
我们能做些什么呢?使用我们自己的不等式谓词,它不会冻结在永远不会被实例化的变量上:
marker_truth(Xs,Truth) :- % variant #2
freeze(Xs, marker_truth__1(Xs,Truth)).
marker_truth__1(Xs,Truth) :-
( Xs = [_|Xs0]
-> freeze(Xs0, marker_truth__2(Xs0,Truth))
; Truth = false
).
marker_truth__2(Xs,Truth) :-
( Xs = [X|Xs0]
-> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
; Truth = false
).
marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
( nonvar(X)
-> ( X == 1
-> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
; Truth = false
)
; Xs0 == []
-> freeze(X,(X == 1 -> Truth = true ; Truth = false))
; Truth = false
).
所有这些代码,用于表达is_marker([_,1]) 的安全逻辑否定? 丑陋!
让我们看看它是否(至少)有助于上述查询(给出这么多无用答案的查询)!
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2, 0],[4,0]],
splitlistIf(marker_truth,Ls,Pss)。
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0] ,[4,0]],
Pss = [[ [_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]]? ;
不
有效!然而,在考虑所需的编码工作时,很明显,无论是代码生成方案还是
必须设计dif/2 的变体(显示上述行为)。
编辑 2015-05-25
以上实现marker_truth/2有点工作,但还有很多不足之处。考虑:
?- marker_truth(M,Truth). % most general use
freeze(M, marker_truth__1(M, Truth)).
这个答案不是我们想要得到的。要了解为什么不这样做,让我们看看integer_truth/2 的类似用法的答案:
?- integer_truth(I,Truth). % most general use
Truth = true, freeze(I, integer(I)) ;
Truth = false, freeze(I, \+integer(I)).
在最一般的情况下有两个答案---这就是具体化谓词的行为方式!
让我们相应地重新编码marker_truth/2:
marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true.
marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false.
marker_truth([_,1],true).
marker_truth(Xs ,false) :- nonMarker__1(Xs).
nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)).
nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg).
nonMarker__1(_).
nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)).
nonMarker__2(T) :- T = [_|_], !, dif(T,[1]).
nonMarker__2(_).
让我们用 marker_truth/2 的新实现重新运行上面的查询:
?- marker_truth(M,Truth). % most general use
Truth = true, M = [_A,1] ;
Truth = false, freeze(M, nonMarker__1(M)).