10.40.4.3 Evaluation Functions

There are two functions in this category: Prolog extended to be able to evaluate Tcl expressions in a Tcl interpreter; Tcl extended to be able to evaluate a Prolog expression in the Prolog system.

There is a mechanism for describing Tcl commands in Prolog as Prolog terms. This is used in two ways: firstly, to be able to represent Tcl commands in Prolog so that they can be subsequently passed to Tcl for evaluation; and secondly for passing terms back from Tcl to Prolog by doing the reverse transformation.

Why not represent a Tcl command as a simple atom or string? This can indeed be done, but commands are often not static and each time they are called require slightly different parameters. This means constructing different atoms or strings for each command in Prolog, which are expensive operations. A better solution is to represent a Tcl command as a Prolog term, something that can be quickly and efficiently constructed and stored by a Prolog system. Variable parts to a Tcl command (for example command arguments) can be passed in through Prolog variables.

In the special command format, a Tcl command is specified as follows.

Command ::= Name
| chars(code-list)
| write(term)
| writeq(term)
| write_canonical(term)
| format(Fmt,Args)
| dq(Command)
| br(Command)
| sqb(Command)
| min(Command)
| dot(ListOfNames)
| list(ListOfCommands)
| ListOfCommands

Fmt ::= atom

Name ::= atom { other than [] }
| number

ListOfCommands ::= []
| [ Command | ListOfCommands ]

ListOfNames ::= []
| [ Name | ListOfNames ]

Args ::= []
| [ term | Args ]

where

Atom
Number
denote their printed representations
chars(PrologString)
denotes the string represented by PrologString (a code-list)
write(Term)
writeq(Term)
write_canonical(Term)
denotes the string that is printed by the corresponding built-in predicate.
Please note: In general it is not possible to reconstruct Term from the string printed by write/1. If Term will be passed back into Prolog it therefore safest to use write_canonical(Term).

format(Fmt, Args)
denotes the string that is printed by the corresponding built-in predicate
dq(Command)
denotes the string specified by Command, enclosed in double quotes
br(Command)
denotes the string specified by Command, enclosed in curly brackets
sqb(Command)
denotes the string specified by Command, enclosed in square brackets
min(Command)
denotes the string specified by Command, immediately preceded by a hyphen
dot(ListOfName)
denotes the widget path specified by ListOfName, preceded by and separated by dots
list(ListOfCommands)
denotes the TCL list with one element for each element in ListOfCommands. This differs from just using ListOfCommands or br(ListOfCommands) when any of the elements contains spaces, braces or other characters treated specially by TCL.
ListOfCommands
denotes the string denoted by each element, separated by spaces. In many cases list(ListOfCommands) is a better choice.

Examples of command specifications and the resulting Tcl code:

     [set, x, 32]
         => set x 32
     [set, x, br([a, b, c])]
         => set x {a b c}
     [dot([panel,value_info,name]), configure, min(text), br(write('$display'/1))]
          => .panel.value_info.name configure -text {$display/1
     ['foo bar',baz]
          =>foo bar baz
     list(['foo bar',bar])
          => {foo bar} baz
     list(['foo { bar'',bar])
          => foo\ \{ \bar baz

Prolog calls Tcl through the predicate tcl_eval/3, which has the following form:

     tcl_eval(+TclInterpreter, +Command, -Result)

which causes the interpreter TclInterpreter to evaluate the Tcl command Command and return the result Result. The result is a string (a code-list) that is the usual return string from evaluating a Tcl command. Command is not just a simple Tcl command string (although that is a possibility) but a Tcl command represented as a Prolog term in the special Command Format (see Evaluation Functions).

Through tcl_eval/3, Prolog has a method of synchronous communication with an embedded Tcl interpreter and a way of manipulating the state of the interpreter.

An example:

     | ?- tcl_new(Interp), 
          tcl_eval(Interp, 'set x 1', _),
          tcl_eval(Interp, 'incr x', R).

which creates a Tcl interpreter the handle of which is stored in the variable Interp. Then variable x is set to the value "1" and then variable x is incremented and the result returned in R as a string. The result will be "2". By evaluating the Tcl commands in separate tcl_eval/3 calls, we show that we are manipulating the state of the Tcl interpreter and that it remembers its state between manipulations.

It is worth mentioning here also that because of the possibility of the Tcl command causing an error to occur in the Tcl interpreter, two new exceptions are added by the tcltk library:

     tcl_error(Goal, Message)
     tk_error(Goal, Message)

where Message is a code-list detailing the reason for the exception. Also two new user:portray_message/2 rules are provided so that any such uncaught exceptions are displayed at the Prolog top-level as

     [TCL ERROR: Goal - Message]
     [TK ERROR: Goal - Message]

respectively.

These exception conditions can be raised/caught/displayed in the usual way through the built-in predicates raise_exception/3, on_exception/1, and portray_message/2.

As an example, the following Prolog code will raise such an exception:

     | ?- tcl_new(X), tcl_eval(X, 'wilbert', R).

which causes a tcl_error/2 exception and prints the following:

     {TCL ERROR: tcl_eval/3 - invalid command name "wilbert"}

assuming that there is no command or procedure defined in Tcl called wilbert.

The Tcl interpreters created through the SICStus Prolog Tcl/Tk library have been extended to allow calls to the underlying Prolog system.

To evaluate a Prolog expression in the Prolog system from a Tcl interpreter, the new prolog Tcl command is invoked. It has the following form:

     prolog PrologGoal

where PrologGoal is the printed form of a Prolog goal. This causes the goal to be executed in Prolog. It will be executed in the user module unless it is prefixed by a module name. Execution is always determinate.

The return value of the command either of the following:

"1"
if execution succeeded,
"0"
if execution failed.

If succeeded (and "1" was returned), any variable in PrologGoal that has become bound to a Prolog term will be returned to Tcl in the Tcl array named prolog_variables with the variable name as index. The term is converted to Tcl using the same conversion as used for Tcl commands (see Evaluation Functions). As a special case the values of unbound variables and variables with names starting with `_', are not recorded and need not conform to the special command format, this is similar to the threatment of such variables by the Prolog top-level.

An example:

     test_callback(Result) :-
         tcl_new(Interp),
         tcl_eval(Interp,
             'if {[prolog "foo(X,Y,Z)"] == 1} \\
                 {list $prolog_variables(X) \\
                       $prolog_variables(Y) \\
                       $prolog_variables(Z)}',
                 Result),
         tcl_delete(Interp).
     
     foo(1, bar, [a, b, c]).

When called with the query:

     | ?- test_callback(Result).

will succeed, binding the variable Result to:

     "1 bar {a b c}"

This is because execution of the tcl_eval/3 predicate causes the execution of the prolog command in Tcl, which executes foo(X, Y, Z) in Prolog making the following bindings: X = 1, Y = bar, Z = [a, b, c]. The bindings are returned to Tcl in the associative array prolog_variables where prolog_variables(X) is "1", prolog_variables(Y) is "bar", and prolog_variables(Z) is "a b c". Then Tcl goes on to execute the list command as

     list "1" "bar" "a b c"

which returns the result

     "1 bar {a b c}"

(remember: nested lists magically get represented with curly brackets) which is the string returned in the Result part of the Tcl call, and is ultimately returned in the Result variable of the top-level call to test_callback(Result).

If an error occurs during execution of the prolog Tcl command, a tcl_error/2 exception will be raised. The message part of the exception will be formed from the string `Exception during Prolog execution: ' appended to the Prolog exception message. An example is the following:

     | ?- tcl_new(T), tcl_eval(T, 'prolog wilbert', R).

which will print

     {TCL ERROR: tcl_eval/3 - Exception during Prolog execution:
       wilbert  existence_error(wilbert,0,procedure,user:wilbert/0,0)}

at the Prolog top-level, assuming that the predicate wilbert/0 is not defined on the Prolog side of the system. (This is a tcl_error exception containing information about the underlying exception, an existence_error exception, which was caused by trying to execute the non-existent predicate wilbert.)


Send feedback on this subject.