0

I'm fairly new to Prolog and I want to create a predicate that behaves as follows

calculate(add(1, sub(4,1)),Result).
Result = 4.

This is doing: 1 + (4 - 1) = 4

I'm familiar with predicates but I don't know where to start in terms of being able to write an add//2 predicate/operator.

Any help or suggestions are much appreciated.

Guy Coder
  • 24,501
  • 8
  • 71
  • 136

2 Answers2

2

You are still thinking in terms of functions

z = f(x,y): "f(x,y) returns (is replaced by/ is reduced to) value z ..."

Predicates relate values to other values:

p_f(x,y,z): "predicate p_ makes a relation/connection/links values (x,y,z) such that z = f(x,y)"

So to pipeline evaluation (mathematical notation (g°f)(x,y) )

g(f(x,y))

you have to write (not respecting the Prolog convention that 'variables' are written in uppercase here):

p_f(x,y,a),p_g(a,b)

And think in terms of information flowing into this expression through p_f(x,y,_), getting transferred to p_g/2 via p_f(_,_,a), p_g(a,_) and flowing out of the expression via p_g(a,b).

And p_f/3 or p_g/2 will fail (return false, not in any of their arguments, but as a whole) if they are unable to relate their arguments and there will be no result.

Using predicates has the advantage that for p_f(x,y) you can request x if y is known, y if x is known, or pairs of valid (x,y) (as long as that is computationally possible and the predicate has been correctly coded). Or for a predicate add/3:

  • add(2,3,X) -> X = 5
  • add(2,3,5) -> true
  • add(X,3,5) -> X = 2
  • add(1,3,5) -> false
  • add(X,Y,5) -> X = 2, Y = 3; X = 3, Y = 2; ... ad infinitum
  • add(X,Y,Z) -> same as above only even more unrestrained

See also: Prolog ~ Splitting a number into a list

David Tonhofer
  • 14,559
  • 5
  • 55
  • 51
2

With a small change on the representation of numbers, we can write a nice solution. The change is to represent the number N as number(N)` to avoid a defaulty representation (meaning, "it's a number by default if it's not an operation):

calculate(number(Number), Number).
calculate(add(Expression1, Expression2), Result) :-
    calculate(Expression1, Result1),
    calculate(Expression2, Result2),
    Result is Result1 + Result2.
calculate(sub(Expression1, Expression2), Result) :-
    calculate(Expression1, Result1),
    calculate(Expression2, Result2),
    Result is Result1 - Result2.

Sample call:

| ?- calculate(add(number(1), sub(number(4), number(1))), Result).

Result = 4
yes
Paulo Moura
  • 18,373
  • 3
  • 23
  • 33
  • Nice noting *defaulty* – Guy Coder Mar 14 '20 at 10:21
  • @GuyCoder Thanks. For more on *defaulty representations*, see the following blog post: https://logtalk.org/2019/12/17/the-cost-of-defaulty-representations.html – Paulo Moura Mar 14 '20 at 10:56
  • 1
    The reason I added the comment was because this question looks like the class has started a new section and as you know that in creating these predicates there are concepts that if they don't understand up front will make getting these predicates to work together much harder, and you are one of the few that uses *defaulty* in your answer which is one of the key concepts needed to do these type of problems correctly. Markus also has a nice section on *defaulty* but I leave finding that to those that seek it. – Guy Coder Mar 14 '20 at 11:07
  • 1
    In case you didn't notice and it has now been approved, there is the tag [prolog-defaulty](https://stackoverflow.com/tags/prolog-defaulty/info) which references your blog. – Guy Coder Mar 16 '20 at 08:57