I know Prolog (programming in logic) is all about returning true and false, and that a function is something which returns anything from lists, to numbers, to boolean values. Initially it doesn't seem that Prolog has the concept of functions but instead relies on unification, yet you can do stuff like:
?- X is log(42).
X = 3.7376696182833684.
So it seems that there exist functions? Or is this really just some sort of syntactic sugar hiding the unification part?
And if it really is just syntactic sugar, then how would I go about if I wanted to define a mathematical 'function' like log2?
Of course I can use unification:
log2(X,Result) :- Result is log(X)/log(2).
But say I want to use the 'syntactic sugar function style' so I can write:
?- X is log2(8).
X = 3.0.
How can I do that in Prolog?
Prolog is about describing relations between entities. Since a mathematical function is a special kind of relation (which relates input to a uniquely defined output), you can use Prolog to describe such functions. In your example, the predicate that implements this relation is called is/2
, and (is)/2
is also defined as an infix operator in Prolog, so you can write:
?- X is log(42).
instead of the prefix form (which is of course also still admissible):
?- is(X, log(42)).
Notice that is/2
performs arithmetic evaluations of expressions, and unifies the first argument with the result. This is different from unification of X
with the Prolog term log(42)
.
Note though that is/2
is not a true relation, because you cannot use it in the other direction:
?- 0 is log(X).
ERROR: is/2: Arguments are not sufficiently instantiated
A solution for this is to use constraints (for example, over real numbers, called CLP(R)), which work in all directions. They are available as libraries or built-ins in many modern Prolog systems.
So it is just unification.. (thanks to mbratch and mat for explanations)
This is how I solve my initial problem, and thus makes my code more readable when using self defined mathematical functions:
:- op(900, xfy, <-).
R <- log2(Y) :- R is log(Y)/log(2), !.
% the two predicates below solves the problem with using mathematical operators
% together with self defined functions note that they should always be last
%
R <- X :-
compound(X),
X =..[OP, X2, X3],
R2 <- X2,
R3 <- X3,
Expr =..[OP, R2, R3],
R is Expr, !.
R <- X :- R is X, !.
then I can write:
?- X <- log2(8).
X = 3.0.
and furthermore the last two predicates makes it possible to write compounds like:
?- X <- 17*log2(8) - 2.
X = 49.0.
Note that you aren't allowed to mess with the is/2, and therefore I am sort of overruling it by using my own <- operator instead
EDIT: added syntactic sugar suggested by mat and added two predicates which fixes problems when using the newly defined log2 in combination with other mathematical operators
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With