"Out of stack" error on a simple Prolog predicate - list

I've been practicing Prolog. The function I'm trying to write is compose(L1, L2, L3). It consists of the element of L1 and L2 interleaved in order until one of them becomes nil, and then appends that non-nil list at the end. The function works perfectly fine when it is given L1 and L2 as input(ie it prints out the correct L3) but I run into an "out of stack" error when I input L3 and try to get all the logically possible inputs L1 and L2. For example, for the following function code,
compose([],[],[]).
compose(L1,[],L3):-
append(L1,[],L3).
compose([],L2,L3):-
append([],L2,L3).
compose([H1|T1],[H2|T2],L3):-
compose(T1,T2,Tail),
append([H1],[H2],Head),
append(Head,Tail,L3).
?-compose(L1,L2,[a,b,c]).
will give me an out of stack error. How should I solve this issue?

How should I solve this issue?
First, try to understand why your query does not terminate. You can try to imagine how Prolog proceeds, but be warned, this can get pretty complex. After all, Prolog combines two control flows (AND- and OR-control) plus it has partially unknown data which do not exist in more traditional languages (OO and FP). For this reason, I prefer not to imitate Prolog, instead I let Prolog help me to localize the error. To this end, I add as many goals false as possible into your program such that the query still does not terminate. Here is the maximum, called a failure-slice:
compose([],[],[]) :- false.
compose(L1,[],L3):- false,
append(L1,[],L3).
compose([],L2,L3):- false,
append([],L2,L3).
compose([H1|T1],[H2|T2],L3):-
compose(T1,T2,Tail), false,
append([H1],[H2],Head),
append(Head,Tail,L3).
?- compose(L1, L2, [a,b,c]), false.
We can skip over your first clauses. Only the first goal of the last rule is of interest! So nothing more than:
compose([H1|T1],[H2|T2],L3):-
compose(T1,T2,Tail), false,
... .
?- compose(L1, L2, [a,b,c]), false.
In this tiny little program, the third argument of compose/3 is completely ignored. Nobody wants L3. And thus, L3 has no influence on termination. To make this terminate we need somehow constrain L3 prior to the goal. The other answer shows you how.
(This method works for any non-termination problem of a pure Prolog program, see failure-slice for more.)

First re-write it as a simpler yet fully equivalent
compose([],[],[]). % some redundancy here
compose(L1,[],L1).
compose([],L2,L2). /*
compose([H1|T1],[H2|T2],L3):- % whole solution
compose(T1,T2,Tail),
Head = [H1,H2],
L3 = [Head|Tail]. */
which now makes it clear the problem is with the recursion, first calculating the rest of the result (Tail), and only then completing it (as L3).
Instead, twist it,
compose([H1|T1],[H2|T2],[H1,H2|Tail]):- % single step
compose(T1,T2,Tail).
so that now we have co-recursion, and a productive one at that. It first creates the (assuredly finite) starting portion of the result, and fills the missing pieces later.
(In the above, "creates" can be interchanged with "consumes", as is the double-directional nature of Prolog. Being single-step, it doesn't care which arguments are consumed, and which are produced).

An "Out of global stack" error usually means that your recursion got stuck in an infinite loop, and thus keeps calling a predicate, until the stack is exhausted.
The reason this here gets in an infinte loop is because it will first emit results:
?- compose(L1,L2,[a,b,c]).
L1 = [a, b, c],
L2 = [] ;
L1 = [],
L2 = [a, b, c] ;
L1 = [a, c],
L2 = [b] ;
But then it will look for more solutions. It does that, based on your program, by each time unifing the first item with [H1|T1], and the second with [H2|T2]. You then immediately make a recursive call, so Prolog can not check if the H1 and the H2 are actually the first two elements in the third parameter.
We however do not need all these append/3 calls, etc. in the first place. We can perform simple unification on the parameters:
compose([],L2,L2).
compose(L1,[],L1).
compose([H1|T1],[H2|T2],[H1, H2|T3]) :-
compose(T1,T2,T3).
For the given query this will terminate after the proposed solution:
?- compose(L1,L2,[a,b,c]).
L1 = [],
L2 = [a, b, c] ;
L1 = [a, b, c],
L2 = [] ;
L1 = [a],
L2 = [b, c] ;
L1 = [a, c],
L2 = [b] ;
false.
Indeed, since due to the recursion, eventually the third parameter will be an empty list, and thus fail to unify with the [H1, H2|T3] list.

Related

Concatenate two lists in turns

I was trying to create a predicate that concatenates two lists in such a way that
test([1,2], [3,4], X) would give X = [1,3,2,4].
My attempt looks like that
test([], [], _).
test([X|L1], [Y|L2], L3) :-
append([X, Y], L3, L4),
test(L1, L2, L4).
The thing is, it only gives true. output, so it seems like my list at the end doesn't get stored under L3 var? I'm not quiet sure how to go around that, I would appreciate any tips.
What you have is a good start and nearly functional. Here are a few comments.
The name test is quite generic and a better name should be used. This is not only a good practice from a readability standpoint, but generic names can often collide with predefined system predicates. In this case, I would choose interleave or zip which are common names for this relationship between two lists.
Your base case test([], [], _) effectively says that the result of operating on two empty lists is any list you want, which clearly isn't logical. It should be interleave([], [], []).
The use of append/3 in append([X,Y], L3, L4) is overkill. You can simply write: L4 = [X,Y|L3], or even more compactly:
interleave([X|L1], [Y|L2], [X,Y|L3]) :-
interleave(L1, L2, L3).
With that single base case, you limit the successful solutions to only include two lists of the same length. If you wish lists of different length, you'd want some additional logic to accommodate. This can be done with just two base cases. Putting it all together, you'd have:
interleave([], L, L). % interleaving the empty list with any list is the same list
interleave([H|T], [], [H|T]). % interleaving any non empty list
% with the empty list is the same list
interleave([X|L1], [Y|L2], [X,Y|L3]) :-
interleave(L1, L2, L3).

list of lists- recursive pairs prolog

how can I put all the pairs in a one list?
I have -
pair([H|T], [H,E]) :- member(E, T).
pair([_|T], P) :- pair(T, P).
and I want the answer will be a list of pairs.
so I try -
listPairs([],[Res1]):-
Res1=[].
listPairs(L,[Res2]):-
L=[H|T],
append(pair([H|T],[Res2]),listPairs(T,[Res2])).
but I miss something of the lists..
because it is not compile.
I don't really see what you aim to do with append/2. You can definitely not put goals that should be called in the append/3 because in that case, they will be seen as functors.
You can however easily use the findall/3 predicate which is implemented in nearly all Prolog systems (well at least all I have seen that are actively used):
listPairs(L,Pairs) :-
findall(Pair,pair(L,Pair),Pairs).
findall/3 works as follows:
findall(Format,Goal,List).
Here you specify a Goal (here pair(L,Pair)) and Prolog will call the Goal. Each time the Goal succeed, Prolog will suspend the interpreter and add en element formatted as Format to the List. When the Goal fails, the list of all Formats is returned.
If I run the query, I get:
?- listPairs([1,a,2,'5'],Pairs).
Pairs = [[1, a], [1, 2], [1, '5'], [a, 2], [a, '5'], [2, '5']].
Note that L must be grounded (as list, meaning without uninstantiated tail, an uninstantiated element is fine), since otherwise the number of pair/2 elements that you will generate is infinite and thus you will run out of global stack (or memory in general).

How do I stop an empty list from appending to a complete list in Prolog?

I have this issue in Prolog where I'm creating a list, and sometimes predicates that contribute to this list creation return an empty list, []. In the end I end up with a list that looks like [[1, 2, 3], []] for example, when I'd rather it be [[1, 2, 3]].
How do I stop that empty list when I return it from being put with the rest of the list? My logic programming isn't terrible strong, but in other languages I'd simply say, if not empty: append, otherwise don't do anything.
Is this possible in Prolog?
EDIT: To put it in an example, say I have the following predicate:
put_together(Value1, Value2, Result) :-
Result = [Value1, Value2].
I call put_together(1, 2, Result). and get Result = [1, 2] as expected. But if I call, put_together(1, [], Result). I get Result = [1, []] which I don't want, I'd rather have the final empty list gone, which would be simply [1].
DCGs are often a good way to describe lists in Prolog. This makes reasoning about lists a lot easier. You should try it in your use case.
For example, to "put together" (see below for why this is not a good view of the matter) two lists, as you say it, you can use:
lists_together(Ls1, Ls2) -->
list(Ls1),
list(Ls2).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Sample cases:
?- phrase(lists_together([a,b,c], [d,e]), Ts).
Ts = [a, b, c, d, e].
?- phrase(lists_together([a,b,c], []), Ts).
Ts = [a, b, c].
This is completely general and works in all directions. Try for example the most general query, or iterative deepening etc. I therefore avoid an imperative name like put_..., which would indicate that it works only in one direction. Instead, I use a more declarative name that does justice to the multiple directions in which this relation holds.
However, in your case, it seems that you are somehow, and involuntarily, mixing terms of different kinds. To denote pairs, do not use [A,B] (which is .(A, .(B, []))), but rather use terms like A-B.
So, to relate such pairs to their components, use for example:
key_value_pair(Key, Value, Key-Value).
If possible, I'd recommend changing your predicates so that you always return lists of lists, and always compose them with append/3. That way, you can absorb empty lists as-if they were zeros in a sum and stop worrying about empty lists being corner cases.
DCG's, as mention in mat's answer, are a possible way to consistently use lists.

How do I get the sum of given numbers in prolog?

I'm new to prolog and I'm doing some exercises for practice. So I'm trying to get the sum of the given numbers in a list. I'm trying to use this:
my_last(X, [X]).
my_last(X, [_|L]) :- my_last(X, L).
(from here)
as my guide. So this is my code for getting the sum:
listsum(X, []).
listsum(X, [H|L]):-
X is H + listsum(X, L).
when I compile it, it says
practice.pl:3: evaluable listsum(_G139,_G140) does not exist
practice.pl:2: Singleton variables: [X]
then when I try listsum(0, [1,2,3]). it returns false.
I still don't understand much about prolog, and list and recursion in prolog.
Arithmetic
As you already discovered, arithmetic can be handled in Prolog with the (is)/2 operator. It's because in Prolog, everything is only symbolic calculus: things don't have a meaning by default, so the unification (=)/2 wouldn't know that (+)/2 refers to the addition for example.
Now, your problem is that you use a regular predicate inside of (is)/2 (here it's your recursive call). Since (is)/2 only performs arithmetic, it doens't evaluate the predicate call. It doesn't even recognize it since it's not an arithmetic function.
The fix here would be to affect the result of the recursive call to a variable and then use it in the (is)/2 call:
listsum(X,[]).
listsum(Result, [Head|Tail]) :-
listsum(SumOfTail, Tail),
Result is Head + SumOfTail.
Base case correctness
But if you test that code you will not get the desired result. The reason is that you have another problem, in your base case. The sum of the empty list isn't "anything", as you stated by writing
listsum(X,[]).
(X is a free variable, hence can be anything).
Instead, it's 0:
listsum(0, []).
The resulting code is:
listsum(0, []).
listsum(Result, [Head|Tail]) :-
listsum(SumOfTail, Tail),
Result is Head + SumOfTail.
Order of arguments
Now, as a sidenote, in Prolog a convention is that output variables should be put at the end of the predicate while input variables should be put at the start of the predicate, so to behave as wanted we could refactor as follows:
listsum([], 0).
listsum([Head|Tail], Result) :-
listsum(Tail, SumOfTail),
Result is Head + SumOfTail.
Tail Call Optimization
Now, we can still improve this predicate with more advanced techniques. For example we could introduce tail calls so that Tail Call Optimization (googlable) could be performed, thanks to an idiom of declarative programming called an accumulator:
listsum(List, Sum) :-
listsum(List, 0, Sum).
listsum([], Accumulator, Accumulator).
listsum([Head|Tail], Accumulator, Result) :-
NewAccumulator is Accumulator + Head,
listsum(Tail, NewAccumulator, Result).
The idea behind that is to update an intermediate result at each step of the recursion (by adding the value of the current head of the list to it) and then just state that when the list is empty this intermediate value is the final value.
Getting more general programs
As you may have noted in Prolog, quite often predicates can be used in several ways. For example, length/2 can be used to discover the length of a list:
?- length([1, 2, 3], Length).
Length = 3.
or to build a skeleton list with free variables of a desired length:
?- length(List, 3).
List = [_G519, _G522, _G525].
Here though, you might have noted that you can't ask Prolog what are the lists which have a sum that is 6:
?- listsum(L, 6).
ERROR: is/2: Arguments are not sufficiently instantiated
That's because, to "go backwards", Prolog would have to solve an equation when comes the call to the (is)/2 operator. And while yours is simple (only additions), arithmetic isn't solvable this way in the general case.
To overcome that problem, constraint programming can be used. A very nice library is available for SWI, clpfd.
The syntax here would be:
:- use_module(library(clpfd)).
listsum(List, Sum) :-
listsum(List, 0, Sum).
listsum([], Accumulator, Accumulator).
listsum([Head|Tail], Accumulator, Result) :-
NewAccumulator #= Accumulator + Head,
listsum(Tail, NewAccumulator, Result).
Now we can use our predicate in this other way we wished we could use it:
?- listsum(L, 6).
L = [6] ;
L = [_G1598, _G1601],
_G1598+_G1601#=6 ;
L = [_G1712, _G1715, _G1718],
_G1712+_G1715#=_G1728,
_G1728+_G1718#=6 . % Here I interrupted the answer but it would not terminate.
We could even ask for all the solutions to the problem:
?- listsum(L, X).
L = [],
X = 0 ;
L = [X],
X in inf..sup ;
L = [_G2649, _G2652],
_G2649+_G2652#=X . % Here I interrupted the answer but it would not terminate
I just mentionned that so that you realize that quite often the use of (is)/2 should be avoided and use of constraint programming should be preferred to get the most general programs.
If possible, use clpfd instead of plain old (is)/2 (and friends).
clpfd offers a logically pure predicate sum/3 that could fit your needs!

Reaching end of list in prolog

I've been given the question:
Define a predicate ordered/1, which checks if a list of integers is correctly in ascending order. For example, the goal ordered([1,3,7,11]) should succeed, as should the goal ordered([1,3,3,7]), whereas the goal ordered([1,7,3,9]) should fail.
So far I have this:
ordered([]).
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
But it fails on every list.
I have deduced that the reason it fails is because it reaches the end number in the list then tries to compare that number against an empty list. Obviously this fails because you can't compare an integer to an empty list. Even if you could and it, say, returned 0 for an empty list, it would still return false as the number would be greater than 0, not less than.
I can't find a solution... Any ideas? Thanks, Jon.
Edit
So, some slightly amended code:
ordered([]).
ordered([N]):-
N >= 0.
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
This now works for ordered([1]), but bigger lists still don't run correctly.
Should I include something like ordered([N, M|Ns]) in the definition?
(assuming this is homework, I hesitate to give a complete solution).
Looking at your code, try to find out how it would unify ?- ordered([1]).
Run this query mentally (or using trace/0) and see what it does, step by step, and how it computes its result.
Also, please try to get "returns a value" out of your mind when thinking prolog. Prolog predicates don't return anything.
I think your solution is not also tail-recursion-friendly.
Think something like that would do:
ordered([]) :-!.
ordered([_]):-!.
ordered([A,B|T]) :-
A =< B,
!,
ordered([B|T]).
If you are using SICStus Prolog,
my previous answer will not work, as the
clpfd library in SICStus Prolog
does not offer the library predicate
chain/3 included with
SWI-Prolog's clpfd library.
:- use_module(library(clpfd)).
:- assert(clpfd:full_answer).
Don't panic! Simply implement predicate ordered/1 like this:
ordered([]).
ordered([X|Xs]) :-
ordered_prev(Xs,X).
ordered_prev([] ,_ ).
ordered_prev([X1|Xs],X0) :-
X0 #=< X1,
ordered_prev(Xs,X1).
Let's see it in action with SICStus Prolog 4.3.2.
Here's the most general query:
?- ordered(Xs).
Xs = []
; Xs = [_A]
; Xs = [_A,_B], _A#=<_B, _A in inf..sup, _B in inf..sup
; Xs = [_A,_B,_C], _A#=<_B, _B#=<_C, _A in inf..sup, _B in inf..sup, _C in inf..sup
... % an infinity of solutions follows: omitted for the sake of brevity.
And here are the queries the OP suggested:
?- ordered([1,3,7,11]).
yes % succeeds deterministically
?- ordered([1,3,3,7]).
yes % succeeds deterministically
?- ordered([1,7,3,9]).
no
Note that both succeeding queries in above example did not leave any useless choicepoints behind, thanks to first argument indexing.
If your Prolog system supports clpfd, check if it offers the library predicate clpfd:chain/2.
:- use_module(library(clpfd)).
If so, simply write:
?- chain([1,3,7,11],#<).
true.
?- chain([1,3,3,7],#=<).
true.
?- chain([1,3,3,7],#<).
false.
?- chain([1,7,3,9],#<).
false.
You're quite right: according to your code there are only two possible ways a list can be ordered:
It's empty
The first two items are in the correct order, and the rest of the list is ordered
Those are certainly both correct statements, but what about the list [3]? Isn't that ordered too? Obviously a list with only one element is ordered, yet you have no provision for expressing that: it fits neither your base case nor your recursive case.
The single-element list is another case hiding here that you haven't addressed yet. Since this is independent of the two rules you've already defined, you might want to consider a way to address this special case separately.
Well that, in the end, was rediculously easy to fix.
Here is the correct code.
ordered([]).
ordered([N, M|Ns]):-
append([M], Ns, Tail),
ordered(Tail),
N =< M.
ordered([M]).
ordered([M]). deals with the single-element list as described above.
The real root of my problem was not including [] around the M in the append function.
Whats the ettiquette regarding awarding the correct answer? You've both helped muchly.
Jon
Don't use append/3.
edit1 to satisfy #false. In order to make it tail recursive friendly it has to eliminate backtracking. This is tail-recursive and only slight variation on #Xonix:
ordered([X|[]]):-!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).
edit2 Take it a step further to eliminate lists that have less than two elements
ordered([X,Y|[]]):- X =< Y,!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).