2

I swear this isn't a homework problem. I haven't attended classes in decades. Once upon a time I came up with a cute recursive formula for the partition function:

         / 0 (k > n)
f(k, n) {  1 (k = n)
         \ p(k, n-k)+p(k+1, n) (k < n)

I thought to try to represent this in prolog. This is about as far as I could get:

partition(N, N, 1) :- !. %% http://stackoverflow.com/a/9582409

partition(K, N, 0) :- K > N.

partition(K, N, A+B) :-
 X is K+1,
 Y is N-K,
 partition(X, N, A),
 partition(K, Y, B).

?- partition(1, 10, X). gives me this:

X = 1+0+0+0+0+1+(1+0+0)+(1+0+0+0+(1+0))+(1+0+0+0+1+(1+0+0)+(1+0+0+1+(1+0+1)))+(1+0+0+0+0+(1+0)+(1+0+0+1)+(1+0+0+0+(1+0)+(1+0+0+(1+0)))+(1+0+0+0+1+(1+0+0)+(1+0+0+1+(1+0+1))+(1+0+0+0+(1+0)+(1+0+0+(1+0))+(1+0+0+1+(1+0+1)+(1+0+0+(1+0)+(1+0+1+(1+0+(1+1)))))))) ?

One thing that's comforting is that there are indeed 42 ones in the above expression(?). I was hoping for X=42. Note the question mark. Yes, there are more matches (apparently infinitely more). The second one is:

X = 1+0+0+0+0+1+(1+0+0)+(1+0+0+0+(1+0))+(1+0+0+0+1+(1+0+0)+(1+0+0+1+(1+0+1)))+(1+0+0+0+0+(1+0)+(1+0+0+1)+(1+0+0+0+(1+0)+(1+0+0+(1+0)))+(1+0+0+0+1+(1+0+0)+(1+0+0+1+(1+0+1))+(1+0+0+0+(1+0)+(1+0+0+(1+0))+(1+0+0+1+(1+0+1)+(1+0+0+(1+0)+(1+0+1+(1+(0+0)+(1+1)))))))) ?

Lori
  • 1,392
  • 1
  • 21
  • 29
  • 1
    Prolog will not evaluate `A+B` in your `partition(K, N, A+B)` clause head. It is just a term in Prolog. You'll need `partition(K, N, R) :- ... , R is A + B.` – lurker Jan 16 '17 at 19:24

1 Answers1

3

I swear this isn't a homework problem. I haven't attended classes in decades.

Calm down, even if it is homework, there is no problem with asking for help given you have done reasonable effort (reasonable is of course subjective, but I think it is ok for the question) yourself and it is more that there is a specific problem with your implementation :).

The problem with your approach is that you - among many - think that Prolog attaches semantics to functors. For Prolog + is not plus, nor it add things together, + is simply a symbol, it does not evaluate it.

There is however a predicate that evaluates expression trees and uses "semantics" most people agree upon. That is the is/2 predicate. So now you can simply modify it to:

partition(K, N, C) :-
    X is K+1,
    Y is N-K,
    partition(X, N, A),
    partition(K, Y, B),
    C is A+B.

Yes, there are more matches (apparently infinitely more).

That's because your last clause has no guard that says K < N, in other words Prolog will backtrack and regardless on how K and N relate to each other, it can always pick the last clauses (except for K == N since there you placed a cut (!)).

You better use a "guard" for your last clause since otherwise it can be called if K < N when backtracking so. So the full code sequence would read something like:

partition(N, N, 1) :- !. %% http://stackoverflow.com/a/9582409

partition(K, N, 0) :- K > N.

partition(K, N, C) :-
    K < N,
    X is K+1,
    Y is N-K,
    partition(X, N, A),
    partition(K, Y, B),
    C is A+B.

Note that there is nothing special with is/2: it is simply a predicate: you could have called it with is(C,A+B) as well. It only is defined in such a way it can be used as infix operator as well.

With the given clauses, the query gives:

?- partition(1, 10, X).
X = 42 ;
false.
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    Why `is(C, A+B)` instead of the more conventional `C is A + B`? – lurker Jan 16 '17 at 19:26
  • 1
    @lurker: I've added a note at the bottom that the two are equivalent. The aim was to not confuse the OP to think that `is/2` is something special in Prolog. It is simply a predicate that attaches semantics to functors. – Willem Van Onsem Jan 16 '17 at 19:28
  • 1
    They already have, e.g., `X is K+1`, so I mixing in `is(C, A+B)` could add rather than detract from confusion (the OP could reasonably think, "Why is it different in that case?") – lurker Jan 16 '17 at 19:29
  • 1
    @lurker: hmm good point. Didn't even noticed the `is` usage (being too much used to it). I've updated the answer and wrote the note in reverse. – Willem Van Onsem Jan 16 '17 at 19:32
  • That's better, but why `false`? And why `false` (`no` on my GNU Prolog install) as a second match? – Lori Jan 16 '17 at 20:16
  • I was aware of syntactic sugar, but thanks, @lurker! – Lori Jan 16 '17 at 20:17
  • 1
    @Lori: well Prolog can give multiple answers on the same query: a function has the property that there is one answer per input tuple, but a predicate can have multiples. After Prolog has found one answer, you can ask if there are more. Prolog says *no*: there is only one answer. – Willem Van Onsem Jan 16 '17 at 20:17