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, JoachimReceived on Tue Aug 06 2024 - 17:16:45 CEST
This archive was generated by hypermail 2.3.0 : Wed Sep 25 2024 - 15:13:21 CEST