|
From: Joachim S. <jsc...@co...> - 2024-08-06 17:16:45
|
On 30/07/2024 15:24, Chris Meudec wrote:
> Hi all,
> I am getting reacquainted with ECLiPSe Prolog after some time with Sicstus, so
> it appears I am rusty.
>
> I have used attributed variables extensively in the past, but I am stuck.
> I have defined an attributed variable and have defined a unification handler,
> but whenever my unification handler fails (as it should) as part of a condition
> in a condition construct (*+Condition -> +Then ; +Else*) the entire construct
> fails rather than executing the Else part.
>
> I have condensed the problem to a short example below.
>
> :- module('try').
> :- meta_attribute('try', [unify:unify_name/2]).
>
> unify_name(_, Attr) :-
> var(Attr).
> unify_name(Term, Attr) :-
> compound(Attr),
> unify_term_name(Term, Attr).
>
> unify_term_name(_{AttrY}, AttrX) :-
> -?->
> AttrX = AttrY.
>
> try :-
> add_attribute(X, try('X')),
> Declarator = X,
> (Declarator = 2 -> %when unification fails here as it should, the
> else part is not executed as expected
> printf("hello there 10", [])
> ;
> printf("hello there 20", [])
> ).
> try :-
> printf("hello there 30", []).
>
> I get 30 printed out but I was expecting 20.
>
> Why? It is rather odd.
>
> With this attribute, I only want it to succeed when unified with a free variable.
>
> I could avoid using the conditional construct in such cases but it does not help
> my understanding and the current behaviour is a little surprising to me.
>
> Thanks,
> Chris
Hi Chris,
Short answer: as a workaround, insert true/0 after the unification(s) that you
expect to trigger the failure:
try :-
add_attribute(X, try('X')),
Declarator = X,
(Declarator = 2, true -> % true/0 forces handlers & waking
printf("hello there 10", [])
;
printf("hello there 20", [])
).
Background: when attributed variables are involved in unifications, the system
invokes the associated unify-handler(s). While in principle this should happen
just after unification, for technical reasons handlers only execute when control
flow reaches the next "trigger point". This is typically after a sequence of
simple goals (such as =/2, simple arithmetic, etc), but before the next regular
subgoal, e.g.
..., X=1, Y=2, Z=3, /*HANDLE X,Y,Z HERE*/ q(...), ...
Unfortunately, owing to a historic design decision for efficiency reasons, cuts
and -> are classified as simple subgoals. This means that handlers may
counter-intuitively slip over and execute _after_ a cut (or a commit to a
conditional branch as in your example).
As shown above, a dummy subgoal (such as true/0) can always be used to instruct
the compiler to insert a handler trigger point at an earlier position.
Regards,
Joachim
|