How can I pass a predicate as a parameter to another predicate in Prolog?

I have these three predicates:

times(X, Y):-
    Result is X * Y.
minus(X, Y):-
    Result is X - Y.
plus(X, Y):-
    Result is X + Y.

      

and I want to transfer, for example, times(2,2)

to plus(X, Y)

like this one plus(times(2,2), minus(X, Y))

.

+3


source to share


3 answers


The relationship between the title of your question and the text of your question is not clear to me, and I think @false is probably correct that there is a more fundamental misunderstanding about Prolog here. I don't know if this really applies to your need or not, but the alternative here is to write your own evaluator.

eval(times(X,Y), Result) :-
    eval(X, XResult),
    eval(Y, YResult),
    Result is XResult * YResult.
eval(minus(X,Y), Result) :-
    eval(X, XResult),
    eval(Y, YResult),
    Result is XResult - YResult.
eval(plus(X,Y), Result) :-
    eval(X, XResult),
    eval(Y, YResult),
    Result is XResult + YResult.

      

Recursive calls eval/2

within the bodies of each of these rules are needed to handle cases such as plus(times(2,2), minus(X, Y))

. Then you need a rule for numbers:

eval(Num, Num) :- number(Num).

      

This is great for cases like this:

?- eval(plus(times(2,2), minus(7,1)), Result).
Result = 10.

      

It won't help you in such cases:



?- eval(plus(times(2,2), minus(X,Y)), Result).
ERROR: Out of local stack

      

Of course it works if we set the bindings for X and Y before we get there, but if you want it to generate possible solutions for X and Y you are out of luck, you need to use clpfd

, The reason for this curious error if you are the trace in is that number(X)

, when X

unrelated, is false, so it actually generates new sentences related to time structures, minus and plus, and tries them, which is not something you want in the evaluator.

Edit : implementationprintterm/1.

The predicate eval/2

shows you how to perform a recursive tree motion. The principle is the same as when creating a beautiful printer. I am very lazy, so I will only draw it, you will have to fill in the details yourself.

printterm(T) :- format_term(T, Formatted), write(Formatted), nl.

format_term(plus(X,Y), Formatted) :- 
  format_term(X, XFormatted),
  format_term(Y, YFormatted),
  format(atom(Formatted), '(~a + ~a)', [XFormatted, YFormatted]).

% other format_term clauses here for other arithmetic expressions

format_term(X, X) :- number(X).

      

Hope this helps!

+4


source


First, you need to understand what Prolog predicates actually describe: they are not functions, but rather relationships between values. Therefore, if you want to have to add a predicate, it must be a predicate with three arguments: plus(A, B, Sum)

. Thus, Prolog does not display the results for free as in many other languages.

Instead

plus(X, Y):-
   Result is X + Y.

      

you need to write

plus(X, Y, Result) :-
   Result is X + Y.

      

What you need next is further progress in intermediate values. In languages ​​that support functions, this is a very simple task. But in Prolog, function symbols are not interpreted. So either you code everything in the relationship, or else you implement your own version (is)/2

. For beginners, stick with the first option rather. Thus, instead of

..., plus(times(2,2), minus(X, Y)) ...

      



now write

..., times(2, 2, R), plus(R, minus(X, Y), S), ...

      

c S

is the end result.

Note that if you code expressions directly in a relationship, you must introduce intermediate variables like R

above.

It's so clear that (direct) relational notation is less elegant for a purpose like this. For very precise areas, Prolog offers expressions in particular (is)/2

, and then in a much more general setting library(clpfd)

.

However, as a beginner, it's a good idea to get used to relational notation first. Better yet, consider learning successive arithmetic . Before use library(clpfd)

and before use (is)/2

.

+4


source


An alternative to Daniel's solution is to look at terms such as plus(times(2,2), minus(5,3))

as expression objects that support a set of operations such as "evaluate" or "differentiate". This allows you to write down goals such as:

| ?- plus(times(2,2), minus(5,3))::evaluate(Result).
Result = 6
yes

      

The advantage is that the rules for all operations that apply to a particular expression, for example, are times/2

neatly encapsulated in the appropriate object. That is, instead of clustering predicates by operations, they are clustered by an (elementary) expression. An example along these lines, but in the context of getting and simplifying expressions, can be found here .

+2


source







All Articles