При смешивании пролога сопрограммирования (заморозка /2, когда /2) и DCG
В моем предыдущем ответе на недавний вопрос " Тест дерева двоичного поиска Пролога - сравнение родительских узлов нежелательных родителей " я предложил смешать lazy_chain/2
который использует пролог-сопроводить...
: - use_module ( библиотека (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)); в противном случае -> domain_error (chain_relation, R_2)). lazy_chain_aux ([], _). lazy_chain_aux ([Z0 | Zs], R_2): - заморозить (Zs, lazy_chain_aux_(Zs,R_2,Z0)). lazy_chain_aux_([], _, _). lazy_chain_aux_([Z1|Zs], R_2, Z0):- вызов (R_2, Z0, Z1), заморозить (Zs, lazy_chain_aux_ (Zs, R_2, Z1)).
... вместе с DCG in_order//1
...
in_order (nil) -> []. in_order(узел (X,L,R)) -> in_order (L), [X], in_order (R).
... вот так:
? - lazy_chain (Zs, # <), фраза (in_order (узел (1, ноль, ноль)), Zs). Zs = [1,23].
Есть ли простой способ "подтолкнуть" lazy_chain
в phrase/3
так что его объем ограничен частью последовательности, описанной in_order//1
?
Прямо сейчас я получаю...
? - lazy_chain (Zs, # <), фраза (in_order (узел (1, ноль, ноль)), Zs0,Zs). Zs0 = [1|Zs], заморозить (Zs, lazy_chain_aux (Zs, # <)).
... который (конечно) может потерпеть неудачу при дальнейшей реализации Zs
:
? - lazy_chain (Zs, # <), фраза (in_order (узел (1, ноль, ноль)), Zs0, Zs), Zs = [3,2,1]. ложь
Как я могу обойти это и ограничить lazy_chain
к части списка разницы?
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].
... сейчас все в порядке, но все же мне интересно: стоит ли это того?
Я не вижу проблем в смешивании сопряжения и DCG. DCG- это только перевод из правил DCG H --> B
, к некоторым обычным правилам Пролога 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.
до свидания