关于混合 Prolog 协程(freeze/2、when/2)和 DCG
On mixing Prolog coroutining (freeze/2, when/2) and DCG
在 my previous answer to the recent question "Prolog binary search tree test - unwanted parents' parent node comparison", I proposed mixing lazy_chain/2
which uses prolog-coroutining ...
:- use_module(library(clpfd)).
lazy_chain(Zs, R_2) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> freeze(Zs, lazy_chain_aux(Zs,R_2))
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_aux([], _).
lazy_chain_aux([Z0|Zs], R_2) :-
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z0)).
lazy_chain_aux_([], _, _).
lazy_chain_aux_([Z1|Zs], R_2, Z0) :-
call(R_2, Z0, Z1),
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z1)).
...连同dcg in_order//1
...
in_order(nil) --> [].
in_order(node(X,L,R)) --> in_order(L), [X], in_order(R).
...像这样:
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs).
Zs = [1,23].
有没有简单的方法把"push"lazy_chain
变成phrase/3
,使其范围限制在in_order//1
描述的序列部分?
现在,我得到...
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs0,Zs).
Zs0 = [1|Zs], freeze(Zs, lazy_chain_aux(Zs,#<)).
...(当然)在 Zs
:
的进一步实例化时可能会失败
?- lazy_chain(Zs, #<),
phrase(in_order(node(1,nil,nil)), Zs0,Zs),
Zs = [3,2,1].
false.
我如何解决这个问题并将 lazy_chain
限制在 list-difference 的一部分?
与此同时,我想到了以下技巧:
lazy_chain_upto(R_2, P_2, Xs0, Xs) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> when((nonvar(Xs0) ; ?=(Xs0,Xs)),
lazy_chain_upto_aux(Xs0,Xs,R_2)),
phrase(P_2, Xs0, Xs)
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_upto_aux(Xs0, Xs, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_aux([], _, _).
lazy_chain_upto_aux([X|Xs0], Xs, R_2) :-
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,X)).
lazy_chain_upto_prev_aux(Xs0, Xs, _, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_prev_aux([], _, _, _).
lazy_chain_upto_prev_aux([B|Xs0], Xs, R_2, A) :-
call(R_2, A, B),
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,B)).
基于此我们可以这样定义in_orderX//1
:
in_orderX(T) --> lazy_chain_upto(#<, in_order(T)).
问题中显示的示例查询...
?- phrase(in_orderX(node(1,nil,nil)), Zs0,Zs), Zs = [3,2,1].
Zs0 = [1,3,2,1], Zs = [3,2,1].
...现在结帐好了,但是我仍然想知道:值得吗?
我没有发现混合使用协程和 DCG 有任何问题。 DCG 只是从 DCG 规则 H --> B
到一些普通的 Prolog 规则 H' :- B'
的翻译。任何约束发布都可以包装到 {}/1
.
这是来自 Quines 的示例:
% eval(+Term, +List, -Term, +Integer)
eval([quote,X], _, X) --> [].
eval([cons,X,Y], E, [A|B]) -->
step,
eval(X, E, A),
eval(Y, E, B).
eval([lambda,X,B], E, [closure,X,B,E]) --> [].
eval([X,Y], E, R) -->
step,
{neq(X, quote), sto(B)},
eval(X, E, [closure,Z,B,F]),
{sto(A)},
eval(Y, E, A),
eval(B, [Z-A|F], R).
eval(S, E, R) -->
{freeze(S, is_symbol(S)), freeze(E, lookup(S, E, R))}.
您可以为 lazy_chain_upto//2
做同样的事情。作为开始你
可以继续定义 lazy_chain_upto//2
的第一个子句
如下:
lazy_chain_upto(R_2, P_2) -->
( {var(R_2)} -> {instantiation_error(R_2)}
; {clpfd:chain_relation(R_2)} -> /* ?? */
; {otherwise} -> {domain_error(chain_relation, R_2)}
)
在 /* ?? */
部分,您也可以从 DCG 化的 lazy_chain_upto_aux//1
谓词中获益。当然,我假设 DCG 翻译理解 (->) 和 (;)/2.
再见
在 my previous answer to the recent question "Prolog binary search tree test - unwanted parents' parent node comparison", I proposed mixing lazy_chain/2
which uses prolog-coroutining ...
:- use_module(library(clpfd)). lazy_chain(Zs, R_2) :- ( var(R_2) -> instantiation_error(R_2) ; clpfd:chain_relation(R_2) -> freeze(Zs, lazy_chain_aux(Zs,R_2)) ; otherwise -> domain_error(chain_relation, R_2) ). lazy_chain_aux([], _). lazy_chain_aux([Z0|Zs], R_2) :- freeze(Zs, lazy_chain_aux_(Zs,R_2,Z0)). lazy_chain_aux_([], _, _). lazy_chain_aux_([Z1|Zs], R_2, Z0) :- call(R_2, Z0, Z1), freeze(Zs, lazy_chain_aux_(Zs,R_2,Z1)).
...连同dcg in_order//1
...
in_order(nil) --> []. in_order(node(X,L,R)) --> in_order(L), [X], in_order(R).
...像这样:
?- lazy_chain(Zs, #<), phrase(in_order(node(1,nil,nil)), Zs). Zs = [1,23].
有没有简单的方法把"push"lazy_chain
变成phrase/3
,使其范围限制在in_order//1
描述的序列部分?
现在,我得到...
?- lazy_chain(Zs, #<), phrase(in_order(node(1,nil,nil)), Zs0,Zs). Zs0 = [1|Zs], freeze(Zs, lazy_chain_aux(Zs,#<)).
...(当然)在 Zs
:
?- lazy_chain(Zs, #<), phrase(in_order(node(1,nil,nil)), Zs0,Zs), Zs = [3,2,1]. false.
我如何解决这个问题并将 lazy_chain
限制在 list-difference 的一部分?
与此同时,我想到了以下技巧:
lazy_chain_upto(R_2, P_2, Xs0, Xs) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> when((nonvar(Xs0) ; ?=(Xs0,Xs)),
lazy_chain_upto_aux(Xs0,Xs,R_2)),
phrase(P_2, Xs0, Xs)
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_upto_aux(Xs0, Xs, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_aux([], _, _).
lazy_chain_upto_aux([X|Xs0], Xs, R_2) :-
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,X)).
lazy_chain_upto_prev_aux(Xs0, Xs, _, _) :-
Xs0 == Xs,
!.
lazy_chain_upto_prev_aux([], _, _, _).
lazy_chain_upto_prev_aux([B|Xs0], Xs, R_2, A) :-
call(R_2, A, B),
when((nonvar(Xs0) ; ?=(Xs0,Xs)), lazy_chain_upto_prev_aux(Xs0,Xs,R_2,B)).
基于此我们可以这样定义in_orderX//1
:
in_orderX(T) --> lazy_chain_upto(#<, in_order(T)).
问题中显示的示例查询...
?- phrase(in_orderX(node(1,nil,nil)), Zs0,Zs), Zs = [3,2,1].
Zs0 = [1,3,2,1], Zs = [3,2,1].
...现在结帐好了,但是我仍然想知道:值得吗?
我没有发现混合使用协程和 DCG 有任何问题。 DCG 只是从 DCG 规则 H --> B
到一些普通的 Prolog 规则 H' :- B'
的翻译。任何约束发布都可以包装到 {}/1
.
这是来自 Quines 的示例:
% eval(+Term, +List, -Term, +Integer)
eval([quote,X], _, X) --> [].
eval([cons,X,Y], E, [A|B]) -->
step,
eval(X, E, A),
eval(Y, E, B).
eval([lambda,X,B], E, [closure,X,B,E]) --> [].
eval([X,Y], E, R) -->
step,
{neq(X, quote), sto(B)},
eval(X, E, [closure,Z,B,F]),
{sto(A)},
eval(Y, E, A),
eval(B, [Z-A|F], R).
eval(S, E, R) -->
{freeze(S, is_symbol(S)), freeze(E, lookup(S, E, R))}.
您可以为 lazy_chain_upto//2
做同样的事情。作为开始你
可以继续定义 lazy_chain_upto//2
的第一个子句
如下:
lazy_chain_upto(R_2, P_2) -->
( {var(R_2)} -> {instantiation_error(R_2)}
; {clpfd:chain_relation(R_2)} -> /* ?? */
; {otherwise} -> {domain_error(chain_relation, R_2)}
)
在 /* ?? */
部分,您也可以从 DCG 化的 lazy_chain_upto_aux//1
谓词中获益。当然,我假设 DCG 翻译理解 (->) 和 (;)/2.
再见