Problem with accumulators in prolog - prolog

While learning Prolog, I'm trying to solve the following problem, using accumulators:
Write a predicate addone2/ whose first argument is a list of integers, and whose second argument is the list of integers obtained by adding 1 to each integer in the first list. For example, the query
addone([1,2,7,2],X).
should give
X = [2,3,8,3].
I created the following code:
addone([], _).
addone([E|Tail], [R|Rs]) :-
NewE is E+1,
append([R|Rs], [NewE], NewRs),
addone(Tail, NewRs).
But it's not working. Can someone tell me why? So, how do I use accumulators in Prolog?
Thanks!

anthares is correct in that you have to refine your base case. However, you are also making things very inefficiently with your append calls. In Prolog, it takes some time to get used to the power of unification, but for example, in this case it helps you to immediately set up your result list. Try the following:
addone([E|Tail], [E1|Rs]) :-
E1 is E+1,
addone(Tail, Rs).
That's really all there is to it. By immediately placing E1 in your second argument's pattern, you have already created the first element of your result list. The remaining elements Rs will be created during the recursion. A very typical Prolog pattern.

The bottom of your recursion should be addone([],[]). in order NewRs to be connected with the []

Related

Prolog: compare three lists, 1st element of list1 to last element of list2 AND second to last element of list3

Write a PROLOG program (i.e., set of predicates) that implements the following function. The program should compare three lists and determine if the first element of the first list is the same as both the last element of the second list and the second to last element of the third list. Call the main predicate: compare(List1, List2, List3).
I went ahead and wrote separate codes for the two separate conditions, which works on its own.
1. 1st item of List1 equals last item of List2.
2. 1st item of List1 equals second to last item of List3.
Now I'm having trouble combining the codes to work together. My train of thought is that condition 1 and condition 2 have to be met separately before the overall condition is met. So somehow I have to run the code for condition 1 and condition 2 on its own but in the same program?? And if both of those return true then I can have something else that says my conditions are met.
compare(List1,List2,List3):- last(true), secondLast(true).
Condition1:
last([HeadList1|RestList1],[HeadList1]).
last([HeadList1|RestList1],[HeadList2|RestList2]) :-
last([HeadList1|RestList1],RestList2).
Condition2:
secondLast([HeadList1|RestList1],[HeadList1,RestList3]).
secondLast([HeadList1|RestList1],[HeadList3|RestList3]) :-
secondLast([HeadList1|RestList1],RestList3).
What I'm expecting:
?- compare([2,8,9,1],[4,5,6,2],[1,2,3]).
yes
?- compare([a,b,c,d,k],[a,c,f,e],[a,s]).
no
With SWI, you can use last/2 and the definition of secondTast/2 from this question:
secondLast([X,_], X).
secondLast([_|T], X) :- secondLast(T, X).
my_compare([H|_],L1,L2):-
last(L1,H),
secondLast(L2,H).
?- my_compare([2,8,9,1],[4,5,6,2],[1,2,3]).
true
?- my_compare([a,b,c,d,k],[a,c,f,e],[a,s]).
false
You can put a cut to avoid the solution false in the first query. This is a first solution, you can get super fancy and use for instance reverse/2 and other predicates to find another solution (but maybe slower).
#damianodamiano suggests an implementation using reverse/2 and I thought it might be interesting to see what it is.
mycompare([H|_], L2, L3) :-
reverse(L2, [H|_]),
reverse(L3, [_, H|_]).
reverse/2 is somewhat more expensive than a list traversal, so this may not be the best way to solve the problem, I think it's worth seeing because it's fairly close to the question as stated and it demonstrates that this problem is solved really by unification and only unification. damianodamiano's solution has a similar property in that you are finding the first thing, H and then showing that H appears in other positions in the other two lists.
Now I have some miscellaneous feedback for you:
You are right to believe that if you have two predicates, say p1 and p2, you can combine them by doing p1, p2. In general, they are going to share variable bindings between them because what you are doing in programming in Prolog is setting up a relationship between certain things.
This is also why singleton "warnings" are actually errors: they reveal cases where you believe there is a relationship, but where Prolog could tell that you didn't share the variable anywhere, so no relationship was established.
Your variable names are really bad. If 99% of all your variable names are the same, you are going to get confused. It would be better to use A and B than HeadList1 and HeadList2. If you must use names like these, simplify to H1 and H2. When you see [X|Y], you know X is a head of a list and Y is a list tail, you do not need to make that information part of the name. Focus on the content of the variable if you can, or the relationship you're trying to establish between the expressions that variable is a part of.
Prolog predicates do not "return true." They can succeed or fail but they are not evaluated like functions: you cannot replace mycompare(A,B,C) with true just because mycompare(A,B,C) succeeds, you cannot assign a value to the result R = mycompare(A,B,C), and you cannot nest predicates like writeln(mycompare(A,B,C)). So break this habit now so you don't confuse yourself further in the future.

Write Prolog ordered predicate

I am trying to write a predicate that succeeds if and only if the numbers in the list are in non-decreasing order. I am having a hard time trying to figure this out. I know that if each element is less than or equal to the previous one then it should return false but I am lost on how to do it.
ordered(L) :-
Recursion should usually be your first thought for approaching any problem in Prolog. This means:
Defining a base case, where you can easily determine that the predicate is true or false
In other cases, splitting the problem into parts - one part you can resolve immediately, another you can resolve recursively. These parts of the problem generally correspond to portions of the list.
In the simplest cases, the recursive logic is simply to apply some test to the first element of the list; if it passes, recursively apply the predicate to the remainder of the list.
In your case I think it is a bit more complex, as there is no meaningful way you can test an individual element for orderedness (and maybe that gives you a hint what the base case is ...).
ordered(L) :- ordered2(L).
% empty list is ordered
ordered2([]) :- true.
% list with one element is ordered
ordered2([_]) :- true.
% list is ordered if two first elements are ordered
% and the rest of list is ordered
ordered2([A,B|T]) :- A=<B, ordered2([B|T]).

Prolog equivalent rule but error in one

I am currently practicing Prolog for an exam and when I studied old exams I came across a problem, where one had to define a predicate which returns the length of a list. (Example: lengthof([a,b,c,d,e,f],Length). evaluates to Length=6.)
My approach was the following:
lengthof([],0).
lengthof(List,LengthNew) :- lengthof([_|List],Length),LengthNew is Length-1.
But it always threw a stack overflow error. I didn't know what I could have done wrong, so I took a look into the solutions. The solution for this problem is the following:
lengthof([],0).
lengthof([_|List],LengthNew) :- lengthof(List,Length),LengthNew is Length+1.
I am now wondering why my approach did not work out. What is wrong with this one? Logically and at first look, I think, that both approaches are equivalent.
lengthof([],0).
this string means that legth of empty list is zero.
lengthof([_|List],LengthNew) :-
lengthof(List,Length),LengthNew is Length+1.
in the rule you say, that no empty list has to consider as first element (_) and other elements (List). And that length of the all list is length of "List" plus one.
But in this rule:
lengthof(List,LengthNew) :-
lengthof([_|List],Length),LengthNew is Length-1.
you say that length of initial list ("List") is length of more big list minus one.
It is true for any list, but it is no solution of your problem, because your code does not calculate length of initial list - instead of this you inclrease initial list endlessly.
Your first rule that process empty list desribes condition of recursion exit. So your second rule must decrease size of list, but you try increase it, so you receive "stack overflow" error.

Swi Prolog Relation

I am trying to write a relation split in Prolog that takes an integer N, a list L of integers, and other parameters, list L is flat. The relation split returns true if the list L can be divided into three subsets, such that the sum of the integers in each subset is strictly less than N. Otherwise, the relation returns false. This is the furthest I've gone so far:
split(list, list, list, list)
split([],[],[],[]).
list_sum([],0).
split([X|L], [X|L1], [X|L2], L3):-
list_sum([Head + Tail]),
list_sum>N,
!,
split(N, L,L1, L2, L3).
?- ERROR: toplevel: Undefined procedure: list_sum/2 (DWIM could not correct goal)
Any help and explanation is highly appreciated.
Basically your problem is that you need to go learn Prolog. I'm not kidding. You're going to fail your class if you think you can get away with this level of "not getting it" and pick up the rest on S.O.
What's that first line, a comment? Put the comment character there.
What is list_sum/2 doing there in the middle of your split/4 definition?
Unless you're trying to create some kind of difference list or destructuring arithmetic, [Head + Tail] will absolutely not do what you want.
What is list_sum>N supposed to mean on the next line? There is only one namespace in Prolog and the language is very, very dependent on getting your capitalization right. Being this sloppy does not bode well.
Why are you cutting on line 7?
Your last line is defining split/5 when the previous two rule heads (I think?) are defining split/4. This cannot be what you mean.
You're pattern-matching on line 4 requires that all three of the lists begin with the same value, which seems like a pretty special special-case considering you have no other in which you meaningfully examine the elements of the lists.
In my opinion this code is totally unsalvagable. Throw it away and start over. And read through a tutorial first.
To your exact question: you have not defined a predicate list_sum with two arguments in the "code" that you have shown. This is what the error is telling you.

Prolog programming - path way to a solution

I am studying prolog at university and facing some problems. What I already found out is just solution to a problem. However, I'm more interested in the way to think, i.e. how to get such solution.
Can somebody give me an advise on this field. I would really appreciate your help.
I give an example I am coping with and also, found a solution on stackoverflow here, but what I looking for is how does he do that, how does he find the answer :)
Write a predicate flatten(List,Flat) that flatten a list, e.g. flatten([a,b,[c,d],[[1,2]],foo],X) will give X=[a,b,c,d,1,2,foo].
This is the answer I found on stackoverflow:
flatten(List, Flattened):-
flatten(List, [], Flattened).
flatten([], Flattened, Flattened).
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
this answer belongs to user gusbro and asked by user Parhs, I have try to find a way to contact user gusbro to ask him how he can derive such answer but I cannot.
Thank you very much.
Well, all I can say is that the way to solve a problem depends largely on the problem itself. There is a set of problems which are amenable to solve using recursion, where Prolog is well suited to solve them.
In this kind of problems, one can derive a solution to a larger problem by dividing it in two or more case classes.
In one class we have the "base cases", where we provide a solution to the problem when the input cannot be further divided into smaller cases.
The other class is the "recursive cases", where we split the input into parts, solve them separately, and then "join" the results to give a solution to this larger input.
In the example for flatten/2 we want to take as input a list of items where each item may also be a list, and the result shall be a list containing all the items from the input. Therefore we split the problem in its cases.
We will use an auxiliary argument to hold the intermediate flattened list, and thats the reason why we implement flatten/3.
Our flatten/2 predicate will therefore just call flatten/3 using an empty list as a starting intermediate flattened list:
flatten(List, Flattened):-
flatten(List, [], Flattened).
Now for the flatten/3 predicate, we have two base cases. The first one deals with an empty list. Note that we cannot further divide the problem when the input is an empty list. In this case we just take the intermediate flattened list as our result.
flatten([], Flattened, Flattened).
We now take the recursive step. This involves taking the input list and dividing the problem in two steps. The first step is to flatten the first item of this input list. The second step will be to recursively flatten the rest of it:
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
Ok, so the call to flatten(Item, L1, Flattened) flattens the first item but passes as intermediate list an unbound variable L1. This is just a trickery so that at the return of the predicate, the variable L1 still remain unbounded and Flattened will be of the form [...|L1] where ... are the flattened items of Item.
The next step, which calls flatten(Tail, L, L1) flattens the rest of the input list and the result is bounded with L1.
Our last clause is really another base case, the one that deals with single items (which are not lists). Therefore we have:
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
which checks whether item is a list and when it is not a list it binds the result as a list with head=Item and as tail the intermediate flattened list.
First, I'll show you my approach to the problem, then I've got some resources for learning to think recursively.
Here's my solution to the problem "flatten a list of lists (of lists ...)". I've annotated it to show how I got there:
First, let's define the public interface to our solution. We define flatten/2. It's body consists of a call to the internal implementation flatten/3, which takes an accumulator, seeded as an empty list.
flatten ( X , R ) :-
flatten ( X , [] , R ) ,
.
That was easy.
The internal predicate flatten/3 is a little more complex, but not very.
First, we have the boundary condition: the empty list. That marks the end of what we need to do, so we unify the accumulator with the result:
flatten( [] , X , X ).
The next (and only) other case is a non-empty list. For this, we examine the head of the list. Our rule here is that it needs to flattened and appended to the result. A good rule of programming is to write descriptive code, and Prolog is itself a descriptive, rather than procedural, language: one describes the solution to the problem and lets the inference engine sort things out.
So...let's describe what needs to happen now, and punt on the mechanics of flattening the head of the list:
flatten( [X|Xs] , T , Y ) :-
flatten_head(X,X1) ,
append( T,X1,T1) ,
flatten( Xs , T1 , Y )
.
That, too, was easy.
That's the essence of the entire solution, right there. We've broken our problem into 3 pieces:
a special case (the empty list)
the normal case (a non-empty list)
what to do with each element in the list (not yet defined).
Let's move on to the implementation of how to flatten a single list element. That's easy, too. We've got two cases, here: the list item might be a list, or it might be something else.
First, the list element might be an unbound variable. We don't want untowards behaviour, like unbounded recursion happening, so let's take care of that straightaway, by disallowing unbound terms (for now). If the element is bound, we try to flatten it by invoking our public interface, flatten\2 again (oooooooh...more recursion!)
This accomplishes two things
First, it tells us whether we've got a list or not: flatten/2 fails if handed something other than a list.
Second, when it succeeds, the job of flatten_head/2 is done.
Here's the code:
flatten-head( X , Y ) :-
nonvar(X) ,
flatten( X , Y )
.
Finally, the last case we have to consider is the case of list elements that aren't lists (unbound vars, atoms or some other prolog term). These are already "flat"...all we need to do is wrap them as a single element list so that the caller (flatten\3) gets consistent semantics for its "return value":
flatten-head( X , [X] ).
Here's the complete code:
flatten ( X , R ) :-
flatten ( X , [] , R )
.
flatten( [] , X , X ) .
flatten( [X|Xs] , T , Y ) :-
flatten_head(X,X1) ,
append( T,X1,T1) ,
flatten( Xs , T1 , Y )
.
flatten-head( X , Y ) :-
nonvar(X) ,
flatten( X , Y )
.
flatten-head( X , [X] ) .
Each individual step is simple. It's identifying the pieces and weaving them together that's difficult (though sometimes, figuring out how to stop the recursion can be less than obvious).
Some Learning Resources
To understand recursion, you must first understand recursion—anonymous
Eric Roberts' Thinking Recursively (1986) is probably the best (only?) book specifically on developing a recursive point-of-view WRT developing software. There is an updated version Thinking Recursively With Java, 20th Anniversary Edition (2006), though I've not seen it.
Both books, of course, are available from the Usual Places: Powell's, Amazon, etc.
http://www.amazon.com/Thinking-Recursively-Eric-S-Roberts/dp/0471816523
http://www.amazon.com/Thinking-Recursively-Java-Eric-Roberts/dp/0471701467
http://www.powells.com/biblio/61-9780471816522-2
http://www.powells.com/biblio/72-9780471701460-0
You might also want to read Douglas Hofstadtler's classic Gödel, Escher, Bach: An Eternal Golden Braid Some consider it to be the best book ever written. YMMV.
Also available from the Usual Suspects:
http://www.powells.com/biblio/62-9780140289206-1
http://www.amazon.com/Godel-Escher-Bach-Eternal-Golden/dp/0465026567
A new book, though not directly about recursive theory, that might be useful, though I've not seen it (it's gotten good reviews) is Michael Corballis' The Recursive Mind:
The Origins of Human Language, Thought, and Civilization

Resources