I am really stuck on a problem in Prolog. I am trying to make a generator "gen_lists_of_pairs(V, L)", which, given a list of natural numbers V, generates all possible lists containing two-element lists, such that their elements are unique and every element is in the form [A, B] where A and B are members of V and A < B. However, the generator seems to get stuck in an infinite loop trying the same thing over and over. I am new to prolog and I have had generators that are stuck attempting infinite possibilities, but I cannot fathom why in the world prolog gets stuck here..
This is my code:
ascending([_]).
ascending([A, B|L]) :- A < B, ascending([B|L]).
gen_list_of_pairs(_, []).
gen_list_of_pairs(V, [[X,Y]|L]) :-
gen_list_of_pairs(V, L),
member(X, V),
member(Y, V),
ascending([X, Y]),
not((member([X, Y], L))).
And this is the debug trace when calling "gen_list_of_pairs([1], X).":
Call:gen_list_of_pairs([1], _7086)
Exit:gen_list_of_pairs([1], [])
X = []
Redo:gen_list_of_pairs([1], _7086)
Call:gen_list_of_pairs([1], _7902)
Exit:gen_list_of_pairs([1], [])
Call:lists:member(_7906, [1])
Exit:lists:member(1, [1])
Call:lists:member(_7912, [1])
Exit:lists:member(1, [1])
Call:ascending([1, 1])
Call:1<1
Fail:1<1
Fail:ascending([1, 1])
Redo:gen_list_of_pairs([1], _7902)
Call:gen_list_of_pairs([1], _7920)
Exit:gen_list_of_pairs([1], [])
Call:lists:member(_7924, [1])
Exit:lists:member(1, [1])
Call:lists:member(_7930, [1])
Exit:lists:member(1, [1])
Call:ascending([1, 1])
Call:1<1
Fail:1<1
Fail:ascending([1, 1])
Redo:gen_list_of_pairs([1], _7920)
...
As you can see, after outputting "X = []", prolog gets stuck in an infinite loop, trying the pair [1,1] over and over and over, even though as far as my scarce knowledge goes, it should either attempt something else or stop the query after failing an attempt... I cannot whatsoever figure this out and am growing increasingly frustrated. Any help would be greatly appreciated...
There is too much recursion in there. Especially as you are recursing "on the left"
gen_list_of_pairs(V, [[X,Y]|L]) :-
gen_list_of_pairs(V, L), ...
With the second argument uninstantiated, this goes off to infinity, no matter what comes afterwards:
gen_list_of_pairs(V, [[X,Y]|L]) :-
gen_list_of_pairs(V, L),false.
Then:
?- gen_list_of_pairs([1,2,3],X).
ERROR: Stack limit (1.0Gb) exceeded
... because there is no stopping criterium. We just pile on [X,Y] to an ever-lengthening list.
It's better to start afresh.
In fact, the task of appending to the "Bag of Solution" is being taken care of by bagof/3 and setof/3.
We just need to generate new pairs, backtrackably, from V:
gimme_another_pair(V,[X,Y]) :-
member(X,V),
member(Y,V),
X < Y.
Then
?- gimme_another_pair([1,2,3],P).
P = [1, 2] ;
P = [1, 3] ;
P = [2, 3] ;
false.
And so:
gen_list_of_pairs(V, Result) :- setof(P,gimme_another_pair(V,P),Result).
And so:
?- gen_list_of_pairs([1,2,3],X).
X = [[1, 2], [1, 3], [2, 3]].
Related
I'm having trouble figuring out how to find the sum of the integers that are in a list of pairs like so:
[[a, 1], [b, 2], [c, 3], [d, 4]]
I tried something like this, since it is reminiscent of a regular sum function:
sum([], 0).
sum([[_,Head]|[_,Tail]], Sum) :-
sum([_,Tail], Sum2),
Sum is Head+Sum2.
With the call being:
sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total),
write('Sum = '), write(Total).
But that doesn't work. It prints out false, when it should print out the sum, which would be 10 here.
In your attempt to define the predicate sum/2, you're not handling the lists of lists correctly. Try:
sum(Lists, Sum) :-
sum(Lists, 0, Sum).
sum([], Sum, Sum).
sum([[_,N]| Lists], Sum0, Sum) :-
Sum1 is Sum0 + N,
sum(Lists, Sum1, Sum).
This version uses an accumulator to enable a tail-recursive definition. Sample call:
| ?- sum([[a, 1], [b, 2], [c, 3], [d, 4]], Sum).
Sum = 10
yes
I think it might help to split this into two tasks:
create a new list of the second item of each sublist; and
sum up that list.
This makes it easier to tackle the two problems, and furthermore you now have two extra predicates that can be used for other purposes.
We can obtain a list of the second item of the sublists with:
item2list([], []).
item2list([[_, X|_]|T], [X|T2]) :-
item2list(T, T2).
or we can use maplist/3 [swi-doc] and nth1/3 [swi-doc]:
item2list(L1, L2) :-
maplist(nth1(2), L1, L2).
or we can write item2list in terms of findall/3 [swi-doc] and member/2 [swi-doc]:
item2list(L1, L2) :-
findall(X, member([_,X|_], L1), L2).
although here the predicate is not bidirectional.
For example:
?- item2list([[a, 1], [b, 2], [c, 3], [d, 4]], L).
L = [1, 2, 3, 4].
I leave summing up that list as an exercise.
Whenever a goal fails that you expect to succeed, see this as an opportunity to learn (short form for logic earn = earn logic). After all, this is Prolog which was meant to mean Programming in Logic. So where is the logic in your program?
For the moment your program fails, but you expected it to succeed. Where is the culprit? Let's generalize your program such that the resulting program still fails, but is much smaller. There are two easy ways to generalize a program:
remove goals (by adding a prefix *)
remove terms (replacing term by _/*term*/
We can do this pretty blindly. No need to understand your program. Just recheck that the goal still fails. Here is what I came up with on my first try:
:- op(950, fy, *).
* _G_0. % ignore the argument _G_0
sum([], _/*0*/).
sum([_/*[_,Head]*/|[_,Tail]], Sum) :-
* sum([_,Tail], Sum2),
* Sum is Head+Sum2.
?- sum([_/*[a, 1]*/, _/*[b, 2]*/, _/*[c, 3]*/, _/*[d, 4]*/], Total).
false. % gnah - still fails
One problem has to be in the remaining visible part. Too difficult to figure out? Let Prolog explain it to you by querying the most general query:
?- sum(Xs, Sum).
Xs = []
; Xs = [_A,_B,_C].
So only two lengths of lists are possible: The empty list and a list with three elements. Note that we have currently a generalized version of the predicate. So there is no guarantee that we will find solutions for both lengths. However, we can be 100% sure that for all other lengths there will be no solution.
Let's get back at the original program and ask the most general query:
?- sum(Os, Total).
Os = [], Total = 0
; false.
Oh no, there is a single solution only. And not even a single solution for sum([_|_], Total).
So let's generalize the program again but now with respect to this failing goal:
sum([], _/*0*/).
sum([_/*[_,Head]*/|[_,Tail|_/*[]*/]], Sum) :-
sum([_,Tail], Sum2),
* Sum is Head+Sum2.
?- Os = [_|_], sum(Os, Total).
false.
In this part there must be a further error. And in fact, the goal sum([_,Tail], Sum2) is the culprit: It is about a list of exactly two elements, but the rule wants at least three
For the actual fixes, see the other answers.
This method works for pure, monotonic programs such as yours.
I want to write a reverse/2 function. This is my code and I cannot figure out where the error is.
rev([]).
rev([H|T],X):-rev(T,X),append(T,H,_).
The output:
rev ([1,2,3,4], X).
false.
rev(?List1,?List2) is true when elements of List2 are in reversed order compared to List1
rev(Xs, Ys) :-
rev(Xs, [], Ys, Ys).
rev([], Ys, Ys, []).
rev([X|Xs], Rs, Ys, [_|Bound]) :-
rev(Xs, [X|Rs], Ys, Bound).
Output:
?- rev([1,2,3,4],X).
X = [4, 3, 2, 1].
?- rev([3,4,a,56,b,c],X).
X = [c, b, 56, a, 4, 3].
Explanation of rev/4
On call rev([X|Xs](1), Rs(2), Ys(3), [_|Bound](4))
[X|Xs](1) - List1, the input list in our case (we can either call rev(Z,[3,2,1]).)
Rs(2) - ResultList is a helping list, we start with an empty list and on every recursive call we push (adding as head member) a member from [X|Xs](1).
Ys(3) - List2, the output list (reversed list of List1)
[_|Bound](4) - HelpingList for bounding the length of Ys(3) (for iterating "length of Ys" times).
On every recursion call rev(Xs(5), [X|Rs](6), Ys(3), Bound(7)).,
we push head member X ([X|Xs](1)) to the front of Rs ([X|Rs](6)),
and iterating the next member of Ys (Bound(7),[_|Bound](4)).
The recursion ends when rev([](9), Ys(10), Ys(3), [](12)). is true.
Every [X|Xs](1) (now the list is empty [](9)) member moved in reversed order to Ys(10), we bounded the size of Ys(3) (using [_|Bound](4) and now it's empty [](12)).
Notice that append/3 - append(?List1, ?List2, ?List1AndList2).
was wrong used in your code, append(T,H,_) when H is not a List2 (it's the head member of the list).
Example use of append/2 and append/3:
?- append([[1,2],[3]],X). % append/2 - Concatenate a list of lists.
X = [1, 2, 3].
?- append([4],[5],X). % append/3 - X is the concatenation of List1 and List2
X = [4, 5].
You should not place a space between the functor name rev and the argument list. Usually this gives a syntax error:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- rev ([1,2,3],X).
ERROR: Syntax error: Operator expected
ERROR: rev
ERROR: ** here **
ERROR: ([1,2,3],X) .
Otherwise I think the rev/4 solution aims at a bidirectional solution. If you don't need this, and want to go for an accumulator solution that doesn't leave a choice point, you can try:
reverse(X, Y) :-
reverse2(X, [], Y).
reverse2([], X, X).
reverse2([X|Y], Z, T) :-
reverse2(Y, [X|Z], T).
So I am having a list of lists [[],[1],[2,3]] and I want to merge this into a single list.
This is was I tried so far I GNU Prolog:
function([],[]).
function([Varlist|Vars],Var):-
function(Varlist,Var1),
function(Vars,Var2),
append(Var1,Var2,Var).
but this fails when I get the number 1 out, been trying for hours now.
Hope you can help : )
If you consider this generalization:
function1(L, L).
function1([Varlist|Vars],Var) :-
function1(Varlist,Var1),
function1(Vars,Var2),
append(Var1,Var2,Var).
you will see that we get more than required:
?- function1([[],[1],[2,3]], R).
R = [[], [1], [2, 3]] ;
R = [[1], [2, 3]] ;
R = [1, [2, 3]] ;
R = [1, 2, 3] ;
false.
We should keep just the last solution. Not so easy... Revert to original code:
function2([], []).
function2([Varlist|Vars],Var) :-
...
If we assume Varlist is a list, then we will use immediately as argument to append/3 to get Var, and we just recurse to 'flat out' Vars (remaining list of lists)
function2([], []).
function2([Varlist|Vars], Var) :-
function2(Vars, VarTemp1),
append(Varlist, VarTemp1, Var).
Indeed so we solve the problem:
?- function2([[],[1],[2,3]], R).
R = [1, 2, 3].
but there is a bug, not easy to spot. It turns out that solving it also make the procedure more efficient. See if you can find the bug and solve it...
I have written a program that can take a list and change it into a tree.
build_tree([X,Y],'Tree'(X,Y)) :- !.
build_tree([X|Y],'Tree'(X,Z)) :- build_tree(Y, Z).
If I want to reverse the process and take the tree and change it back into a list, how would I do this?
Note that your tree->list conversion isn't a function since trees may correspond to multiple lists:
?- build_tree([1, 2, 3], T).
T = 'Tree'(1, 'Tree'(2, 3)).
?- build_tree([1, 'Tree'(2, 3)], T).
T = 'Tree'(1, 'Tree'(2, 3)).
If you want a predicate that can generate all lists from a tree, remove the cut from build_tree and apply it with a variable first argument. If you want a deterministic conversion, write a new predicate tree_to_list.
Just curious, how would that deterministic version play out? Assuming there was only one possible list, from the tree, for example:
('Tree'('Tree'(nil, 2, nil), 5, 'Tree'(nil, 6, nil)).
Which gives: L = [5, 2, 6]
If you remove the cut from the first rule, your code it's ready to work in 'backward' mode:
?- build_tree([1,2,3,4],T).
T = 'Tree'(1, 'Tree'(2, 'Tree'(3, 4))) ;
false.
?- build_tree(X,$T).
X = [1, 'Tree'(2, 'Tree'(3, 4))] ;
X = [1, 2, 'Tree'(3, 4)] ;
X = [1, 2, 3, 4] ;
false.
flatten(leaf, []).
flatten(node(L, E, R), Ls) :-
flatten(L, Ls1),
append(Ls1, [E], Ls2),
flatten(R, Ls3),
append(Ls2, Ls3, Ls).
if you consider tree ass node(leaf,Element,leaf) for example
flatten(node(node(leaf,2,leaf),3,node(leaf,5,leaf)),X).
gives X=[2,3,5].
and if you wanna have bst
List to Tree.
insert(E,leaf,node(leaf,E,leaf)).
insert(E,node(L,N,R),T) :-
E >= N,
T=node(L,N,R1),
insert(E,R,R1).
insert(E,node(L,N,R),T) :-
E < N,
T=node(L1,N,R),
insert(E,L,L1).
list_to_tree(List,Tree) :-
list_to_tree(List,leaf,Trea2),
Tree=Trea2.
list_to_tree([],Tree,Tree).
list_to_tree([H|T],Tree,St):-
insert(H,Tree,R),
list_to_tree(T,R,St).
I need to write a program in Prolog that should remove every second element of a list. Should work this: [1,2,3,4,5,6,7] -> [1,3,5,7]
so far I have this, but it just returns "false".
r([], []).
r([H|[T1|T]], R) :- del(T1,[H[T1|T]], R), r(R).
del(X,[X|L],L).
del(X,[Y|L],[Y|L1]):- del(X,L,L1).
This is pretty much Landei's answer in specific Prolog syntax:
r([], []).
r([X], [X]).
r([X,_|Xs], [X|Ys]) :- r(Xs, Ys).
The second predicate is not required.
Alternative solution using foldl/4:
fold_step(Item, true:[Item|Tail], false:Tail).
fold_step(_Item, false:Tail, true:Tail).
odd(List, Odd) :-
foldl(fold_step, List, true:Odd, _:[]).
Usage:
?- odd([1, 2, 3, 4, 5, 6, 7], Odd).
Odd = [1, 3, 5, 7]
The idea is to go through the list, while keeping "odd/even" flag and flipping its value (false -> true, true -> false) on each element. We also gradually construct the list, by appending those elements which have "odd/even" flag equal to true, and skipping others.
This fine answer by #code_x386 utilizes difference-lists and foldl/4.
Let's use only one fold_step/3 clause and make the relation more general, like so:
fold_step(X, [X|Xs]+Ys, Ys+Xs).
list_odds_evens(List, Odds, Evens) :-
foldl(fold_step, List, Odds+Evens, []+[]).
Sample queries:
?– list_odds_evens([a,b,c,d,e,f], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e]
?– list_odds_evens([a,b,c,d,e,f,g], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e,g]
Edit
Why not use one clause less and do away with predicate fold_step/3?
lambda to the rescue!
:- use_module(library(lambda)).
list_odds_evens(List, Odds, Evens) :-
foldl(\X^([X|Xs]+Ys)^(Ys+Xs)^true, List, Odds+Evens, []+[]).
Another possibility is to use DCGs, they are usually a worthwhile consideration when describing lists:
list_oddindices(L,O) :-
phrase(oddindices(L),O). % the list O is described by oddindices//1
oddindices([]) --> % if L is empty
[]. % O is empty as well
oddindices([X]) --> % if L has just one element
[X]. % it's in O
oddindices([O,_E|OEs]) --> % if L's head consists of at least two elements
[O], % the first is in O
oddindices(OEs). % the same holds for the tail
This is certainly less elegant than the solutions using foldl/4 but the code is very easily readable, yet it solves the task described by the OP and works both ways as well:
?- list_oddindices([1,2,3,4,5,6,7],O).
O = [1, 3, 5, 7] ;
false.
?- list_oddindices(L,[1,3,5,7]).
L = [1, _G4412, 3, _G4418, 5, _G4424, 7] ;
L = [1, _G4412, 3, _G4418, 5, _G4424, 7, _G4430] ;
false.
I have no Prolog here to try it out, and I got a little bit rusty, but it should be along the lines of
r([]) :- [].
r([X]) :- [X].
r([X,Y|Z]) :- R=r(Z),[X|R].
[Edit]
Of course pad is right. My solution would work in functional languages like Haskell or Erlang:
--Haskell
r [] = []
r [x] = [x]
r (x:_:xs) = x : (r xs)
In Prolog you have to "pull" the right sides into the argument list in order to trigger unification.
I just needed a function like this and took a more "mathematical" approach:
odds(Xs, Ys) :- findall(X, (nth1(I,Xs,X), I mod 2 =:= 1), Ys).
It doesn't work both ways like some of the other fine answers here, but it's short and sweet.