Prolog unifies a variable with a term then forgets the unification - prolog

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 :-).

Related

Finding number of unique elements in the list

I want to write a code which will return number of unique elements in the list. My idea is to check if head of the list is there in the list of uniqeue elemeents. If it is not, add it to the list and increment the counter and continue witht the remaining list. So, I tried out following:
count([],0).
count([X,T], N) :-
count([X,T], [], N). %initially list of unique elements is empty
count([X,T], U, N) :- % U is a list of unique elements
(not(member(X, U)), append(U, X, U2));
count(T, U2, N1),
N is N1 + 1.
%------ helpers ------
member_(X,[Y|T]):-
member_(X, T).
member_(X,[X|_]).
append([], Y, [Y]). % append[] and Y to get Y.
append([H|X], Y, [H|Z]) :- append(X, Y, Z). % append [H|X] and Y to get [H|Z] if appending X and Y gives Z
But running above simply return false:
3 ?- count([1,2,3],N).
Call: (10) count([1, 2, 3], _7714) ? creep
Fail: (10) count([1, 2, 3], _7714) ? creep
false.
Why is this so?
But running above simply return false:
3 ?- count([1,2,3],N).
Call: (10) count([1, 2, 3], _7714) ? creep
Fail: (10) count([1, 2, 3], _7714) ? creep
false.
Why is this so?
Because there is no head of a clause that count([1,2,3],N) can match.
You have two clauses for count/2:
count([],0). %%% clause 1
count([X,T], N) :- ... %%% clause 2
Since [1,2,3] can't be unified with [], clause 1 is no match.
But [1,2,3] can also not be unified with [X,T], thus clause 2 is also no match. Therefore, count([1,2,3],N) cannot be proven.
You can test this by asking
?- [X,T]=[1,2,3].
false.
What you need to recursively break down lists of arbitrary length is [X|T] instead. (Please test ?- [X|T]=[1,2,3]. to see how you could fix your code.)

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 - Why does my definition for append_list not return the combined list?

% appends an element to the beginning of a list.
append_element(X, T, [X|T]).
% append a list to another list to create a combined list,
% by breaking the first list apart, and using append_element.
append_list([], L, L).
append_list([H|T], L, NewList) :-
append_element(H, L, NL),
append_list(T, NL, NL).
When I try to run append_list,
?- append_list([1,2], [3, 4, 5], NL).
I get back false. Instead of
NL = [2, 1, 3, 4, 5].
Why?

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.

simple prolog explanation of string manipulation

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.)

Resources