simple prolog explanation of string manipulation - prolog

just need a simple explanation.. trying to piece everything still together here.
lastitem([X|Xs],Out) :- lastitem(Xs,Out).
here is trace on: lastitem([a,b,c],X).
[trace] 8 ?- lastitem([a,b,c],X).
Call: (6) lastitem([a, b, c], _G536) ? creep
Call: (7) lastitem([b, c], _G536) ? creep
Call: (8) lastitem([c], _G536) ? creep
Exit: (8) lastitem([c], c) ? creep
Exit: (7) lastitem([b, c], c) ? creep
step 1 says if lastitem(something,somethign) exists then listem([X|Xs],Out].. so A is cut out.
step 2-3 does the same.. but w/ B and C.
now question is what happens w/ the empty list in step 4?
why does the empty list not fulfill lastitem(Xs,Out)? or am I solving incorrectly?
Also a verbal explanation of backtracing would help.. because in append I'm really getting twisted. Append has no goals to solve between steps.. yet reverse does not.. nor does my answer above.. if you trace it you can see the X variable is always the same in reverse or this example. in append it changes.
append([],L,L).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).
append([a, b, c], [1, 2, 3], _G518) % <-- variable L3 continues to change
append([b, c], [1, 2, 3], _G587) % <-- same
append([c], [1, 2, 3], _G590) % < -- same
append([], [1, 2, 3], _G593) % <-- same
append([], [1, 2, 3], [1, 2, 3])
append([c], [1, 2, 3], [c, 1, 2, 3])
append([b, c], [1, 2, 3], [b, c, 1, 2, 3])
append([a, b, c], [1, 2, 3], [a, b, c, 1, 2, 3])
X = [a, b, c, 1, 2, 3]

Just as you, I'm confused by the absence of a base case in lastitem. Are you sure it wasn't actually defined as
lastitem([X|[]], X).
lastitem([X|Xs],Out):- lastitem(Xs,Out).
or something similar?
As for all the backtraces, try to not think too imperatively when looking at Prolog code.
For example, append can be "translated" to a more usual functional definition:
function append(xs, ys) =
if xs is [] then
return ys
else
let [H|L] = xs
return [H | append(L, ys)]
Unterstanding this goes a long way to understanding the Prolog version :)

In lastitem([X|Xs],Out) :- lastitem(Xs,Out)., on both sides the second argument is Out, so it has to stay the same.
In append([H|T],L2,[H|L3]) :- append(T,L2,L3)., the third argument on the left side is [H|L3], but on the right side it's L3, so when you call append, you have a “variable” for [H|L3], but the variable for L3 has to be different. The variable names like _G536 are global, so when they represent different things, they have to be different.
(Sorry for imprecise terminology, I haven't worked with Prolog for a while.)

Related

Unusual behaviour of findall

The following looks very unusual :
?- findall(X, member(X, [1, 2, 3]), X).
X = [1, 2, 3].
The trace even more so
?- trace, findall(X, member(X, [1, 2, 3]), X).
^ Call: (11) findall(_100058, member(_100058, [1, 2, 3]), _100058) ? creep
^ Exit: (11) findall([1, 2, 3], user:member([1, 2, 3], [1, 2, 3]), [1, 2, 3]) ? creep
X = [1, 2, 3]
Thinking in terms of semantics of findall this makes little sense. What is going on?
To expand on my comments, maybe this might help:
?- findall(X, member(X, [1, 2, 3]), Xs).
Xs = [1, 2, 3].
If you look closely, you will see that Prolog (SWI, in this case) did not print a substitution for X. This means that X is not bound when the query succeeds. Indeed:
?- findall(X, member(X, [1, 2, 3]), Xs), var(X).
Xs = [1, 2, 3].
This does not mean that X is never bound while the query executes:
?- findall(X, ( member(X, [1, 2, 3]), writeln(X) ), Xs), var(X).
1
2
3
Xs = [1, 2, 3].
But after all solutions have been generated, X is unbound and can be bound to some other value -- such as the list of solutions. This will work in any standard conforming Prolog, as the standard says explicitly that findall only tries to unify its third argument after it has created the list of solutions. It even contains an example with sharing between the template and the list of instantiations:
findall(X, (X=1;X=2), [X, Y]).
Succeeds, unifying X with 1, and Y with 2.
So how does this binding and unbinding work? With a failure-driven loop, as quoted in rajashekar's answer from the SWI-Prolog implementation. In general, succeeding predicates bind some variables. When at some later point something fails (or, equivalently, the user presses ; when prompted by the toplevel), backtracking takes place: It unbinds variables to allow them to take new values, then retries some goal.
What goes on inside findall is the same as goes on when you write the following:
?- ( member(X, [1, 2, 3]), writeln(X), false ; true ), var(X).
1
2
3
true.
So while findall is very impure, it is not so impure as to be completely un-Prolog-like. In fact, we can write our own:
:- dynamic my_findall_bag/1.
my_findall(Template, Goal, Instances) :-
% initialization
retractall(my_findall_bag(_)),
asserta(my_findall_bag([])),
% collect solutions
( call(Goal),
copy_term(Template, NewSolution),
retract(my_findall_bag(PreviousSolutions)),
asserta(my_findall_bag([NewSolution | PreviousSolutions])),
% failure-driven loop: after saving the solution, force Goal to
% generate a new one
false
; true ),
% cleanup and finish; the saved solutions are in reversed order (newest
% first), so reverse them
retract(my_findall_bag(AllSavedSolutions)),
reverse(AllSavedSolutions, Instances).
This behaves as expected:
?- my_findall(X, member(X, [1, 2, 3]), Xs).
Xs = [1, 2, 3].
Or even:
?- my_findall(X, member(X, [1, 2, 3]), X).
X = [1, 2, 3].
A minor problem with this is that the instantiation of Goal should be checked. A major problem with this is that all my_findall calls share the same bag, so calling my_findall from inside a my_findall (or in parallel) will make you unhappy. This could be fixed using some sort of gensym mechanism to give each my_findall run its unique key into the database.
As for the trace output, it is an unfortunate consequence of wanting to express "your goal succeeded with such-and-such bindings" on one line. At the point of success, it is true that findall(X, ..., X) succeeded, and it is true that X = [1, 2, 3], and hence it is true that the successful instance of the goal is findall([1, 2, 3], ..., [1, 2, 3]).
Consider:
forty_two(FortyTwo) :-
var(FortyTwo),
FortyTwo = 42.
my_call(Goal) :-
format('about to call ~w~n', [Goal]),
call(Goal),
format('success: ~w~n', [Goal]).
For example:
?- my_call(forty_two(X)).
about to call forty_two(_2320)
success: forty_two(42)
X = 42.
So forty_two(42) is a succeeding instance of forty_two(X). Even though forty_two(42) does not succeed:
?- forty_two(42).
false.
It is logical that printing the term forty_two(X) in an environment with X = 42 prints forty_two(42). I think the problem is that this logical behavior sticks out as strange among all the non-logical stuff going on here.
I did some code diving to try and figure out what is going on. In swi-prolog listing(findall, [source(true)]). gives the following code :
findall(Templ, Goal, List) :-
findall(Templ, Goal, List, []).
findall(Templ, Goal, List, Tail) :-
setup_call_cleanup(
'$new_findall_bag',
findall_loop(Templ, Goal, List, Tail),
'$destroy_findall_bag').
findall_loop in the appropriate file is as follows :
findall_loop(Templ, Goal, List, Tail) :-
( Goal,
'$add_findall_bag'(Templ) % fails
; '$collect_findall_bag'(List, Tail)
).
After consulting the C source files, I found out that findall/4 is setting up a global variable in C-source ('$new_findall_bag') and findall_loop/4 is pushing the Templ to it when the Goal succeeds (with '$add_findall_bag'(Templ)). When the Goal fails Templ is uninstantiated and hence the final clause '$collect_findall_bag'(List, Tail) succeeds even when List and Templ are the same variable.
We can see in trace that Templ is usuall uninstantiated.
?- trace, findall(X, member(X, [1, 2, 3]), Xs).
^ Call: (11) findall(_28906, member(_28906, [1, 2, 3]), _28916) ? creep
^ Exit: (11) findall(_28906, user:member(_28906, [1, 2, 3]), [1, 2, 3]) ? creep
Xs = [1, 2, 3].
So the process of finding all instantiations of Templ so that the Goal succeeds is separate from the process of collecting all those instantiations into the variable List and hence we can use the same variable without causing and error. But the semantics of writing such a clause is not making much sense to me.
EDIT: Similar situation occurs in gprolog, where the process of collecting solutions and that of retriving them are separate. Relevant Yap code also looks quite similar, but i was not able to install it to check.

Prolog unifies a variable with a term then forgets the unification

I have the following predicate which I have written for recognising when two lists are the same except the two elements at indices I1 and I2 are swapped:
swapped(I1, I2, List, NewList) :-
% The lists are the same length and the two indices are swapped.
same_length(List, NewList),
nth0(I1, List, V1), nth0(I2, List, V2),
nth0(I1, NewList, V2), nth0(I2, NewList, V1),
% All the other indices remain the same.
proper_length(List, Length), Lim is Length - 1,
numlist(0, Lim, Indices),
forall((member(I, Indices), I \= I1, I \= I2),
(nth0(I, List, V), nth0(I, NewList, V))).
The following swipl output demonstrates my issue:
?- swapped(0, 1, [1,2,3], L).
L = [2, 1, _G5035].
?- swapped(0, 1, [1,2,3], [2,1,3]).
true.
?- swapped(0, 1, [1,2,3], [2,1,4]).
false.
Why does it return a variable for the third element rather than just 3, given that it can recognise that 3 is the only correct term? These are the last four parts of the trace where the unification happens and is then forgotten:
Call: (10) lists:nth0(2, [2, 1, _G6121], 3) ? creep
Exit: (10) lists:nth0(2, [2, 1, 3], 3) ? creep
^ Exit: (8) forall(user: (member(_G6145, [0, 1, 2]), _G6145\=0, _G6145\=1), user: (nth0(_G6145, [1, 2, 3], _G6162), nth0(_G6145, [2, 1, _G6121], _G6162))) ? creep
Exit: (7) swapped(0, 1, [1, 2, 3], [2, 1, _G6121]) ? creep
I don't doubt there's a better way to swap two elements (perhaps recursively) but I would like to know why this is happening and how to fix it; I'm clearly lacking in some Prolog knowledge.
Thanks!
forall/2 is a so called 'failure driven loop'. Then instantiations are undone between cycles.
In SWI-Prolog, there is foreach/2, that fixes the problem with your first query.
...
numlist(0, Lim, Indices),
foreach((member(I, Indices), I \= I1, I \= I2),
(nth0(I, List, V), nth0(I, NewList, V))).
Test:
?- swapped(0, 1, [1,2,3], L).
L = [2, 1, 3].
In SWI-Prolog, sometime the better way to understand a builtin is to inspect the source. You can see that foreach/2 is a fairly complicated predicate... from swipl prompt, try ?- edit(foreach)., or follow the source link from the doc page (the circled :-).

delete first three and last three elements from list, and save it to list2 in prolog

I am completely new to Prolog, but I have to do this for a homework. I have tried something like this
delete(_,[],[]).
delete([X,Y,Z],[X,Y,Z|List],Temp) :-
reverse(Temp,List).
But can't figure out, how to implement second delete from reversed list. Maybe I'm doing it all wrong, I'm lost, thanks for answers.
Using append:
delete([A, B, C | End], Middle, [A, B, C, X, Y, Z]) :-
append(Middle, [X, Y, Z], End).
Test run:
?- delete([1,2,3,4,5,6,7,8], L1, L2).
L1 = [4, 5],
L2 = [1, 2, 3, 6, 7, 8]
?- delete([1,2,3], L1, L2).
false.

Is the `append` predicate tail-recursive?

A typical code example of list processing in Prolog is append:
append([], Ys, Ys).
append([X | Xs], Ys, [X | Zs]) :- append(Xs, Ys, Zs).
My question is whether this program is tail recursive or not. I guess not from my experience in functional languages. However, I find it more difficult to judge for Prolog programs. It seems to we have to take unification into consideration.
Yes, your (and hence the Prolog "standard" version of) append/3 is tail-recursive. You can see this easily because the final goal is a call to append/3 itself. Notice that a typical implementation of append in functional languages is not tail recursive, because the final call is an operation equivalent to cons in Lisp, corresponding for example to:
lisp_append([], Ys, Ys).
lisp_append([X|Xs], Ys, Zs) :-
lisp_append(Xs, Ys, Zs0),
Zs = [X|Zs0].
Example query, yielding a local stack overflow because tail call optimization cannot be applied:
?- length(Ls, 10_000_000), lisp_append(Ls, [], _).
ERROR: Out of local stack
Whereas your natural Prolog version of append/3 works:
?- length(Ls, 10_000_000), append(Ls, [], _).
Ls = [_G8, _G11, _G14, _G17, _G20, _G23, _G26, _G29, _G32|...].
Notice that more predicates are naturally tail recursive in Prolog than in functional languages, due to the power of unification which lets you pull the description of partial results before a tail call. +1 for a good question.
No, your code is NOT tail-recursive.
Tail-recursive means that at the bottom of the recursion you get the answer that you ask for at the beginning directly.
If you trace your code, for exampleappend([1,2,3],[a,b,c],Out), your get:
Call:append([1, 2, 3], [a, b, c], _G4702)
Call:append([2, 3], [a, b, c], _G4756)
Call:append([3], [a, b, c], _G4759)
Call:append([], [a, b, c], _G4762)
Exit:append([], [a, b, c], [a, b, c])
Exit:append([3], [a, b, c], [3, a, b, c])
Exit:append([2, 3], [a, b, c], [2, 3, a, b, c])
Exit:append([1, 2, 3], [a, b, c], [1, 2, 3, a, b, c])
The values of the variables(_G4762,_G4759,_G4756) are passed up to _G4702, and _G4702 is the answer.
We may have a tail-recursive version of append:
ap_tail_r([H|T],B,Ac,Out):-
ap_tail_r(T,B,[H|Ac],Out).
ap_tail_r([],B,[H|Ac],Out):-
ap_tail_r([],[H|B],Ac,Out).
ap_tail_r([],Out,[],Out).
Let trace again ap_tail_r([1,2,3],[a,b,c],[],Out):
Call:ap_tail_r([1, 2, 3], [a, b, c], [], _G4786)
Call:ap_tail_r([2, 3], [a, b, c], [1], _G4786)
Call:ap_tail_r([3], [a, b, c], [2, 1], _G4786)
Call:ap_tail_r([], [a, b, c], [3, 2, 1], _G4786)
Call:ap_tail_r([], [3, a, b, c], [2, 1], _G4786)
Call:ap_tail_r([], [2, 3, a, b, c], [1], _G4786)
Call:ap_tail_r([], [1, 2, 3, a, b, c], [], _G4786)
Exit:ap_tail_r([], [1, 2, 3, a, b, c], [], [1, 2, 3, a, b, c])
Exit:ap_tail_r([], [2, 3, a, b, c], [1], [1, 2, 3, a, b, c])
Exit:ap_tail_r([], [3, a, b, c], [2, 1], [1, 2, 3, a, b, c])
Exit:ap_tail_r([], [a, b, c], [3, 2, 1], [1, 2, 3, a, b, c])
Exit:ap_tail_r([3], [a, b, c], [2, 1], [1, 2, 3, a, b, c])
Exit:ap_tail_r([2, 3], [a, b, c], [1], [1, 2, 3, a, b, c])
Exit:ap_tail_r([1, 2, 3], [a, b, c], [], [1, 2, 3, a, b, c])
The only variable that we are keeping tract of is _G4786, which is the answer that we look for at the first place.
What exactly the tail-recursive code does is: a. reverse the first part, b. put the reversed first part to the second part head by head, c. when the reserved first part is empty, the updated second part is the appended result.

Removing element from a list

I know this question has been asked already, but I just want to ask about my specific implementation. I'm writing this function just to practice Prolog and better understand Prolog. Here's what I have:
del(Ele, [H], [H]) :- Ele \= H.
del(Ele, [H|T], [H|New]) :-
Ele \= H,
del(Ele, T, [New]).
The idea is that I will add an element to a new list called New if the element I want to delete is not equal to H. From what I understand, my code isn't working because my code stops when I reach an element where Ele \= H. Any ideas how to fix this?
For example, del(5, [3,4,5,6,7], X) will return false.
Also, are there any better solutions? It seems like a bad solution to keep adding every element in a list to a new list, since this would be slow for a large list. I'd rather just keep the elements currently in the list, find element(s) that match Ele, remove that element, and then return the list.
You have described some cases where del/3 should hold. But these are only cases where Ele is not equal/unifiable to the elements in the list. There are several things missing:
What about the empty list?
What, if Ele is equal to the element?
So you need to add further clauses. (Later you might also remove some, for reasons of redundancy).
If you are using SWI, B, SICStus, or YAP, consider to use dif/2 in place of (\=)/2. prolog-dif
Here is the reason why dif/2 is so helpful in this case. With dif/2 you would have a pure monotonic program. And you could try it out directly:
?- del(5, [3,4,5,6,7], X).
false.
The same problem you had. Let me just restate what the problem is: You expect that something should hold, but it does not. So the relation is too narrowly defined. If I generalize the query, I might get a better answer. Try del(E, [3,4,5,6,7], X). but again the same false. So I'll try an even more general query:
?- del(E, Xs, Ys).
Xs = Ys, Ys = [_A], dif(E,_A)
; ... .
Looks perfect to me! Maybe another answer:
?- del(E, Xs, Ys).
Xs = Ys, Ys = [_A], dif(E,_A)
; Xs = [_A,_B], Ys = [_A|_B], dif(E,_B), dif(E,_A)
; ... .
Now we got an incorrect answer. I will instantiate it a bit to make it better readable:
?- del(e, [a,b], Ys).
Ys = [a|b]
; false.
This answer is clearly incorrect because [a|b] is not a list. And, it's probably the smallest incorrect answer...
What I want to show you by this is that you can most often locate problems without going through it step-by-step. Step-by-step debugging does not even work in imperative languages once you get a more complex control flow (like concurrency) ; and it does not scale at all in Prolog.
Let's trace:
?- trace, del(5, [3,4,5,6,7], X).
Call: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Fail: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
false.
So you can see your code is actually failing when it gets to the 5 because 5 \= 5 is false. Your first rule is never matched because the list has more than one item in it. The second rule recurs "correctly" after finding 5 \= 3 and 5 \= 4 but since you have no 5 = 5 case in any of your rules, the failure happens there.
Incidentally, let's see what happens when 5 does not occur in the list:
?- trace, del(5, [3,4,6,7], X).
Call: (7) del(5, [3, 4, 6, 7], _G350) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 6, 7], [_G473]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [6, 7], [[]]) ? creep
Fail: (9) del(5, [6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 6, 7], [_G473]) ? creep
Fail: (7) del(5, [3, 4, 6, 7], _G350) ? creep
false.
This is why I said "correctly" before: your inductive case isn't right either. For one thing, you have del(Ele, T, [New]) but up above you have del(Ele, [H|T], [H|New]) so you're unwrapping the list an extra time on the right (this is why our trace has [[]] in it). But #false hit the larger issue which is that you simply never account for the case where you actually find what you are looking to delete. :) You also don't handle the case where the list is empty.
It is an unfortunate fact of life that traversing data structures and looking at each item is going to be O(N). Another unfortunate fact is that in functional and declarative languages (languages that lack "assignables") modifying a list means copying at least part of the list. There are more efficient ways to go about this in Prolog (you could use difference lists, for instance) but they will share the same basic problem. Prolog efficiency is a rather large topic. I'd tell you to not worry about it too much up front, but it has a way of becoming your concern pretty quickly. But in this case, no, there isn't really a substantially more efficient approach using destructive updates.

Resources