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


my previous answer 到最近的问题“
Prolog binary search tree test – unwanted parents’ parent node comparison”,我建议混合使用
prolog-coroutining的lazy_chain / 2 …

:- 07003(07004).

lazy_chain(Zs, R_2) :-
   (  07005(R_2)                  -> 07006(R_2)
   ;  clpfd:chain_relation(R_2) -> 07007(Zs, lazy_chain_aux(Zs,R_2))
   ;  07008                 -> 07009(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) :-
   070010(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, #<),
   070012(in_order(node(1,nil,nil)), Zs).
Zs = [1,23].

是否有一种简单的方法可以将lazy_chain“推送”到phrase/3,以便其范围仅限于in_order // 1所描述的序列部分?

现在,我明白了……

?- lazy_chain(Zs, #<),
   070014(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].

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

点赞