2

I'm trying to write a Prolog predicate that can decomposes a given non-negative integer into every possible sum, using a DCG.

For example:

?- s(3, L, []).
L = [3] ? ;
L = [2,1] ? ;
L = [1,2] ? ;
L = [1,1,1] ? ;
false.

I started by writing a predicate which takes a number N and returns L = [1,2,3,...,N]:

mkList(N, L) :-
   m(0, N, L).

m(X, X, []).
m(Y, L, [H|T]) :-
   H is Y+1,
   m(H, L, T).

However, I'm not sure how I can proceed.

s(Input) -->
   { mkList(Input, InputList) },
   { member(X, InputList) },
   [X].

This is what I was going to use, it starts out my running through the list one by one. However, I'm not sure where I should include a rule to find the difference between X and Input.

repeat
  • 18,496
  • 4
  • 54
  • 166
user127992
  • 83
  • 5
  • 1
    What you are showing isn't using a DCG. Have you read the DCG documentation? Also you are saying "non-negative integer" for criteria which would mean valid solutions for `s(3, L, [])` should include, `[0,3]`, `[0,0,3]` and so on. I assume you really mean *positive integers*? – lurker Dec 02 '15 at 20:11
  • The sums should consist of positive integers, yes, that's not what I was referring to as non-negative. I haven't read the documentation, I've just been learning from the online book 'Learn Prolog Now' – user127992 Dec 02 '15 at 20:39
  • Consider the following two very much related answers: http://stackoverflow.com/a/29289431/4609915 and http://stackoverflow.com/a/29305045/4609915. One uses [tag:clpfd], the other one plain Prolog. HTH! – repeat Dec 03 '15 at 04:54
  • @lurker. IMO the question http://stackoverflow.com/q/29270479/4609915 is basically the same, **however** its name just sucks: no wonder why this user127992 did not find it. What would be the proper conduct here? Rename the older question? Let the new question point to the old one? Mark the new question as a duplicate (of a question that the OP never would have found)? *confused* What do you suggest? – repeat Dec 03 '15 at 05:00

2 Answers2

0

The best way to proceed is to think like Prolog, that is, recursively. Yes, you've got recursion. It may even be right, but I'm not following it.

Thinking like this should work:

mkList(Number,List) :-
 pick a number between 1 and number.  It'll be your first addend.
 subtract it from number to get the remainder.
 make a recursive call to handle the remainder.
 patch together List based on the first addend and the list from the recursive call.

Obviously we need to stop when Number is less than 1.

This doesn't use a DCG, but for the life of me I can't see how a DCG is relevant here.

Topological Sort
  • 2,733
  • 2
  • 27
  • 54
  • Thanks, this is helpful. However I'd like to find a way to do it using a DCG. The way I started it has now been edited into the post. – user127992 Dec 02 '15 at 20:46
0

the base case is easy:

all_sum(N) --> [N].

now, we can call recursively if we provide a M between 1 and N, and take the rest R (beware it must be > 0)

all_sum(N) --> {...},[M],all_sum(R).

please fill the dots using the hints above. You will get

?- phrase(all_sum(3),L).
L = [3] ;
L = [1, 2] ;
L = [1, 1, 1] ;
L = [2, 1] ;
false.
CapelliC
  • 59,646
  • 5
  • 47
  • 90