This discussion seems to have died so some motivation to see if a solution can be found:
The top level prints out answers as variable bindings in lexical order. This is natural and easy to understand. Any attributed variables are listed after the variable bindings as residual goals (as generated by attribute_goals
) but are not listed in lexical order and include additional “attvars” which don’t appear in the the top level goal, but are referenced by other attvars. Presumably they are generated in the order in which the attvar tree (or graph) is walked, but the end result appears to be quite random to the end-user.
This is a non-issue for programs which don’t use attributed variables, or even those which do, but end up “resolving” most or all of the residual goals before the answer is generated. A few attvars at the end of the bindings list is no big deal. But if there’s more than that, the ability to easily “read” the answer is impacted quite a bit.
Usually intervals of real numbers, implemented as attvars, are never be resolved due to floating point rounding. The answers to programs using interval arithmetic are usually dominated by these attvars (as opposed to variable bindings). Another answer example: analysis of a simple D.C. circuit (details unimportant)
?- LI=[Is,I1,I2,I3,I4,I5,I6,I7,I8,I9],simpleCircuit(LI),solve(LI).
LI = [Is, 10, I2, I3, I4, I5, I6, I7, I8|...],
I1 = 10,
Is:: 10.8282986...,
I8:: 0.2592087...,
I2:: 0.5690898...,
I5:: 0.2572598...,
I9:: 0.0389787...,
I3:: -0.3118300...,
I4:: 0.5320600...,
I6:: 0.2962385...,
I7:: 0.8282986... ;
false.
The Ix
's are intervals with one exception; I1
has be unified with the point value 10
. IMO the readability of the answer would be significantly improved if the lexical order of the query was preserved in the answer. The ideal order would be the lexical order independent of whether the original query var is bound to a value or remains an attvar.
How might this be achieved? While the output format of an attvar is determined by the module that defines it (via a call to attribute_goal
), the order is determined by the SWIP top level. One simple fix I’ve tested is modifying copy_term/3
to sort the attvars prior to generating the residual goals. While not a pure lexical ordering of the anser (bindings still before residual goals), it’s a big improvement:
?- LI=[Is,I1,I2,I3,I4,I5,I6,I7,I8,I9],simpleCircuit(LI),solve(LI).
LI = [Is, 10, I2, I3, I4, I5, I6, I7, I8, I9],
I1 = 10,
Is:: 10.8282986...,
I2:: 0.5690898...,
I3:: -0.3118300...,
I4:: 0.5320600...,
I5:: 0.2572598...,
I6:: 0.2962385...,
I7:: 0.8282986...,
I8:: 0.2592087...,
I9:: 0.0389787... ;
false.
This is more than acceptable (to me) and seems to have no affect on the dif
and clpfd
residual goals on simple examples. (It’s hard to imagine how any code could depend on the attvar ordering produced by term_attvars
.) Alternatives would be to change term_attvars
to produce an ordered list; a small gain in efficiency which probably isn’t worth the trouble. Or to modify the top-level code, which would be an opportunity to output the pure lexical order. My guess is that this would be somewhat more complicated for not a lot of gain.
Any other suggestions for solving my admittedly niche problem?