2016-01-15 2 views
4

В my previous answer на недавний вопрос "Prolog binary search tree test - unwanted parents' parent node comparison", я предложил смешивание lazy_chain/2, который использует ...При смешивании Пролог coroutining (заморозить/2, когда/2) и DCG

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

Есть ли простой способ «надавить» 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 со стороны ?

+0

Почему 'в противном случае'? – false

ответ

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

... сейчас проверено в порядке, , но все еще интересно: стоит ли это?

0

Я не вижу никаких проблем со смещением и 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 понимает (->) и (;)/2.

Bye

Смежные вопросы