Functions and Return Values

 

Visual Prolog includes syntax for letting predicates be considered functions having a return value, rather than plain predicates using an output argument. The difference is a bit more than syntactic, however. Because return values are stored in registers, Prolog functions can return values to, and get return values from, foreign languages, but that's an issue covered in the chapter 18.

A function declaration looks like an ordinary predicate declaration, except that the name is prefixed by the domain it's returning:

    PREDICATES
        unsigned triple(unsigned)

However, the clauses for a function should have an extra last argument, to be unified with the return value upon success:

    CLAUSES
       triple(N,Tpl):- Tpl = N*3.

    GOAL
   
    TVal = triple(6), write(TVal).

The return value need not be one of the standard domains, it can be any domain.

If you declare a function that doesn't take any arguments, you must supply an empty pair of brackets when calling it, in order to distinguish it from a string symbol. Given for instance a function to return the hour of the day

    PREDICATES
        unsigned hour()

    CLAUSES
        hour(H):- time(H,_,_,_).

you must call it like this:

    ..., Hour = hour(), ...

and not like this

    ..., Hour = hour, ...

as this will simply consider hour to be the text string "hour", following which the compiler will complain about type errors once you try to use Hour.

It is also recommended to supply an empty pair of brackets in the declaration of functions and predicates having no arguments. If not, confusing syntax errors may result from misunderstandings between predicate names and domain names, if they clash. If for instance you have a domain named key and you also have a predicate named key, then the declaration:

    PREDICATES
        key
        mypred

can be interpreted in two ways: 1) a predicate named key and a predicate named mypred; 2) a predicate name mypred returning a key. If instead you write:

    PREDICATES
        key()
        mypred()

all ambiguity is resolved.

Note that when a predicate is declared as a function, having a return value, it cannot be called as an ordinary Prolog predicate using the extra argument as an output argument; it must be called as a function. The reason for this is that functions store return values in registers, meaning that the code compiled before and in particular after a function call is different from the code around a call of an ordinary predicate. For the same reason, functions calling themselves are currently not tail recursive but this may change in future versions of Visual Prolog.

For instance, if you write a function neg to negate each element in a list, like this:

it is not tail-recursive, while neg as a predicate:

is tail-recursive. Therefore, don't overdo the use of functions. Their primary aim is to enable you to get returned values from, and return values to, foreign language routines.

As a final note, you should be aware that functions with arithmetic return values must be deterministic if they take part in arithmetic expressions.