Previous Up Next

9.6  Non-logical Variables

Non-logical variables in ECLiPSe are a means of storing a copy of a Prolog term under a name (an atom). The atom is the name and the associated term is the value of the non-logical variable. This term may be of any form, whether an integer or a huge compound structure. Note that the associated term is being copied and so if it is not ground, the retrieved term is not strictly identical to the stored one but is a variant of it1. There are two fundamental operations that can be performed on a non-logical variable: setting the variable (giving it a value), and referencing the variable (finding the value currently associated with it).

The value of a non-logical variable is set using the setval/2 predicate. This has the format

setval(NameValue)

For instance, the goal

setval(firm, 3)

gives the non-logical variable firm the value 3. The value of a non-logical variable is retrieved using the getval/2 predicate.

The goal

getval(firm, X)

will unify X to the value of the non-logical variable firm, which has been previously set by setval/2. If no value has been previously set, the call raises an exception. If the value of a non-logical variable is an integer, the predicates incval/1 and decval/1 may be used toincrement and decrement the value of the variable, respectively. The predicates incval/1 and decval/1 may be used e.g., in a failure-driven loop to provide an incremental count across failures as in the example:

count_solutions(Goal, _) :-
        setval(count, 0),
        call(Goal),
        incval(count),
        fail.
count_solutions(_, N) :-
        getval(count, N).

However, code like this should be used carefully. Apart from being a non-logical feature, it also causes the code to be not reentrant. That is, if count_solutions/2 were called recursively from inside Goal, this would smash the counter and yield incorrect results.2

The visibility of a non-logical variable is local to the module where it is first set. It is good style to declare them using local/1 variable/1 declarations. For example, in the above example one should use

:- local variable(count).

If it is necessary to access the value of a variable in other modules, exported access predicates should be provided.


1
Though this feature could be used to make a copy of a term with new variables, it is cleaner and more efficient to use copy_term/2 for that purpose
2
A similar problem can occur when the counter is used by an interrupt handler.

Previous Up Next