Traditionally in Prolog, "functions" (with one output and bound inputs) were written as regular predicates:
mangle(X,Y) :- Y is (X*5)+2.
This can create the difficulty that if a function-style predicate is called multiple times, it is necessary to "daisy chain" temporary variables.
multimangle(X,Y) :- mangle(X,A), mangle(A,B), mangle(B,Y).
In most Prologs, it is possible to avoid this by writing an alternate infix operator to use in place of is
which expands expressions including the alternative function.
% Define the new infix operator
:- op(900, xfy, <-).
% Define our function in terms of the infix operator - note the cut to avoid
% the choice falling through
R <- mangle(X) :- R is (X*5)+2, !.
% To make the new operator compatible with is..
R <- X :-
compound(X), % If the input is a compound/function
X =.. [OP, X2, X3], % Deconstruct it
R2 <- X2, % Recurse to evaluate the arguments
R3 <- X3,
Expr =.. [OP, R2, R3], % Rebuild a compound with the evaluated arguments
R is Expr, % And send it to is
!.
R <- X :- R is X, !. % If it's not a compound, just use is directly
We can now write:
multimangle(X,Y) :- X <- mangle(mangle(mangle(Y))).
However, some modern Prologs go further and offer a custom syntax for this type of predicate. For example, in Visual Prolog:
mangle(X) = Y :- Y = ((X*5)+2).
multimangle(X,Y) :- Y = mangle(mangle(mangle(X))).
Note that the <-
operator and the functional-style predicate above still behave as relations - it is legal for them to have choice points and perform multiple unification. In the first example, we prevent this using cuts. In Visual Prolog, it is normal to use the functional syntax for relations and choice points are created in the normal way - for example, the goal X = (std::fromTo(1,10))*10
succeeds with bindings X=10, X=20, X=30, X=40, etc.