So I just started Prolog and I was wondering two things:
1) Is there built in functions (or are they all called predicates?) for simple things like max of 2 numbers, or sine of a number, etc... If so, how do I access them?
2) How can I call a predicate from another one? I wrote two predicates called car and cdr. car returns the head of a list and cdr returns the list without the head. But now I want to call car on the cdr. Here are some examples for clarification:
car([3,4,5,5], H). would return H = 3
cdr([3,4,5,5],L). would return L = [4,5,5]
and what I am asking is how can I do this:
car(cdr[3,4,5,5]))
??
As others have pointed out, the predicates in Prolog are called that for a reason: they really aren't functions. Many newcomers to Prolog start out by trying to map the functionality they know in other languages over to Prolog and it generally fails. Prolog is a very different programming tool than most other languages. So it's a bit like using a variety of hammers for a long time, then having someone hand you a wrench, and you wonder why it doesn't make a good hammer.
In Prolog, predicates are a means of declaring relations between entities. If you say foo(a, b)
it means there's a relationship between a
and b
called foo
. You've probably seen the examples: knows(joe, jim).
and knows(jim, sally).
And you can define a relation, like:
remotely_acquainted(X, Y) :- knows(X, Z), knows(Z, Y), \+ knows(X, Y).
Or something like that.
A predicate does not return a value. It either succeeds or it fails. If you have a sequence of predicates separated by commas (an "and" relationship) and Prolog encounters a predicate that fails, it backs up (backtracks) to the nearest prior predicate which it can make succeed again with different instantiation of its arguments and moves forward again.
Just to add a little to the confusion, there are some predicates in Prolog designed specifically for the evaluation of arithmetic expressions. These act like functions, but they are special case. For example:
X is Y / gcd(Z, 4).
Here, gcd
of Z
and 4
is computed an its value returned, and then Y
is divided by that value and the result is instantiated into X. There are a variety of other functions as well, such as max/2
, sin/1
, etc. You can look them up in the documentation.
Arithmetic comparative operators function this way as well (using =:=/2
, >/2
, </2
, etc with numeric expressions). So if you say:
X < Y + Z
The Prolog will consider numerical evaluation of these arguments and then compare them.
So having said all that, Prolog does allow embedding of term structures. You could have something like:
car(cdr([1,2,3]))
as a term. Prolog will not interpret it. Interpretation is left up to the programmer. I could then create a predicate which defines an evaluation of such terms:
car([H|_], H).
cdr([_|T], T).
proc_list(car(X), Result) :-
proc_list(X, R1),
car(R1, Result), !.
proc_list(cdr(X), Result) :-
proc_list(X, R1),
cdr(R1, Result), !.
proc_list(X, X).
The cut in the above clauses prevents backtracking to proc_list(X, X)
when I don't want it.
Then:
| ?- proc_list(car(cdr([1,2,3])), R).
R = 2
yes
| ?- proc_list(car(cdr(cdr([1,2,3]))), R).
R = 3
yes
| ?-
Note this is a simple case and I may not have captured all of the subtleties of doing a proper sequence of car
and cdr
. It can also be made more general using =..
and call
, etc, instead of discrete terms car
and cdr
in the parameters. For example, a slightly more general proc_list
might be:
proc_list(Term, Result) :-
Term =.. [Proc, X], % Assumes terms have just one argument
member(Proc, [car, cdr]), % True only on recognized terms
proc_list(X, R1), % Recursively process embedded term
ProcCall =.. [Proc, R1, Result], % Construct a calling term with Result
call(ProcCall), !.
proc_list(X, X).
This technique of processing a term does step away from relational behavior which Prolog is best at, and leans into functional behavior, but with an understand of how Prolog works.
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