混合Prolog coroutining(freeze / 2,when / 2)和DCG

时间:2016-01-15 09:08:41

标签: prolog dcg prolog-coroutining

在最近问题&{34; my previous answer "的Prolog binary search tree test - unwanted parents' parent node comparison中,我建议混合使用lazy_chain/2 ...

:- 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)).

...与 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].

是否有一种轻松的方式来推动&#34; 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约束到的部分?

2 个答案:

答案 0 :(得分:2)

与此同时,我提出了以下黑客行为:

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

...现在检查好了,仍然我想知道:值得吗?

答案 1 :(得分:0)

我没有看到混合corouting和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-ifyed lazy_chain_upto_aux//1谓词中获益。当然我假设DCG翻译理解( - &gt;)和(;)/ 2。

再见