Reputation: 964
I have create a prolog program which given a Number a List and Sublist will generate sublists containing N items in each. I am told this can be done with 1 fact and 2 rules. I am given the hint that I chose the first item or I dont which is confusing me. I have the base case and the first case but I hope someone can help me understand the second case.
choose(1, [H], [H]).
choose(N, [H,TL], [H|ST]) :- choose(Less1, TL, ST), Less1 is N-1.
So my third rule I want to choose the second item in the list
choose(N, [F,S|T], [S|ST]) :- choose(Less1, T, ST), Less1 is N-1.
My last rule however is unbalanced and the whole does not work. Any ideas are greatly appreciated!
Upvotes: 1
Views: 1300
Reputation: 18726
While this previous answer by @madanasta should already point you in the right direction, we extend on it in this answer by using clpfd:
:- use_module(library(clpfd)).
We define n_from_chosen/3
like this:
n_from_chosen(0,_,[]). n_from_chosen(N,[X|Es],[X|Xs]) :- N #> 0, N #= N0+1, n_from_chosen(N0,Es,Xs). n_from_chosen(N,[_|Es],Xs) :- N #> 0, n_from_chosen(N,Es,Xs).
Sample query:
?- n_from_chosen(2,[1,2,3,4],Xs). Xs = [1,2] ; Xs = [1,3] ; Xs = [1,4] ; Xs = [2,3] ; Xs = [2,4] ; Xs = [3,4] ; false.
How about this more general query?
?- n_from_chosen(N,[1,2,3],Xs). N = 0, Xs = [] ; N = 1, Xs = [1] ; N = 2, Xs = [1,2] ; N = 3, Xs = [1,2,3] ; N = 2, Xs = [1, 3] ; N = 1, Xs = [2 ] ; N = 2, Xs = [2,3] ; N = 1, Xs = [3] ; false.
Upvotes: 2
Reputation: 119
The idea behind the first two clauses is correct in principle. However:
Given these, a solution to your problem might be:
choose(1, [H|_], [H]).
choose(N, [H|TL], [H|ST]) :- Less1 is N - 1, choose(Less1, TL, ST).
choose(N, [_|T], L) :- choose(N, T, L).
An attempt to explain:
Thanks to the third clause, Prolog will be able to provide alternative solutions for requested lengths either equal to or greater than 1.
Some results:
?- choose(2, [1,2,3,4], L).
L = [1, 2] ;
L = [1, 3] ;
L = [1, 4] ;
L = [2, 3] ;
L = [2, 4] ;
L = [3, 4] ;
false.
Note that you cannot use this to solve queries with an unbound length variable as you could using @repeat's solution. To achieve that in pure Prolog you would have to change the logic behind the second clause a bit:
choose(N, [H|TL], [H|ST]) :- choose(Less1, TL, ST), N is Less1 + 1.
This might also help clarify how recursion works in this case.
Hope this helps.
(Disclaimer: I am fairly certain that one can provide a far better explanation of how the above solution works (not to mention a better solution).)
Upvotes: 1