Can someone please help explain this copy function works? - list

copyList([], []). % base case
copyList([H|T], [H|R]) :-
copyList(T, R).
I "sort of" understand how recursion works, but when I analysed this function, I got really confused. Can someone please explain, step-by-step what happens in this function and how it reaches the end using the example below:
?- copyList([1,2,3],L).

To understand what happens, you must see Prolog as a theorem solver: when you give Prolog the query ?- copyList([1, 2, 3], L)., you're essentially asking Prolog to prove that copyList([1, 2, 3], L) is true.
Prolog will therefore try to prove it. At its disposal, it has two clauses:
copyList([], []).
copyList([H|T], [H|R]):-
copyList(T, R).
As it is the first that it encounters, Prolog wil try to prove that copyList([1, 2, 3], L) is true by using the clause copyList([], []).
To do so, and since the clause has no body (nothing after :-), it would just have to unify the arguments of your query with the arguments of the clause (unify [1, 2, 3] with [] and L with []). While it is easy to unify L5 with [] (with the unification L5 = []), it is impossible to unify [1, 2, 3] with []. Therefore Prolog has failed to prove your query by using the first clause at its disposal. It must then try to use the second.
Once again it will unify the query arguments with the clause arguments to see if the clause is applicable: here it can do so, with the unifications H = 1, T = [2, 3], L = [H|R]. Now it has to see if the conditions listed after :- are respected, so it has to prove copyList(T, R). The exact same thing goes on twice, until it finds itself trying to prove copyList([], R). There, the first clause is applicable, and its job is over.
You can sum up the execution with a drawing as follows:
copyList([1, 2, 3], L).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and L = [1|R]
|
` copyList([2, 3], R).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R = [2|R2]
|
` copyList([3], R2).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R2 = [3|R3]
|
` copyList([], R3).
|
| use clause number 1 and R3 = []. One solution found
| try to use clause number 2, doesn't unify with arguments.
| No more possibilities to explore, execution over.
Now that the execution is over, we can see what the original L is by following the chain of unifications:
L = [1|R]
R = [2|R2]
R2 = [3|R3]
R3 = []
R2 = [3]
R = [2, 3]
L = [1, 2, 3]
Thanks to Will Ness for his original idea on how to explain the final value of a variable.

While your specific question was already answered, few remarks.
First, you could just as well call ?- copyList(L,[1,2,3]). or ?- copyList([1,2,3],[1,2|Z]). etc. What's important is that both lists can be of equal length, and their elements at the corresponding positions can be equal (be unified), because the meaning of the predicate is that its two argument lists are the same - i.e. of the same length, and having the same elements.
For example, the first condition can be violated with the call
?- copyList(X, [A|X]).
because it says that the 2nd argument is one element longer than the first. Of course such solution can not be, but the query will never terminate, because the first clause won't ever match and the second always will.

Related

Shifting a list N times using Prolog [] issue :- Exercise 3.6 “ Prolog Programming for Artificial Intelligence” by Ivan Btrako

I want to create a predicate shift(List1,List2) where List2 is List1 shifted rotationally by one element to the left.
Example:
?- shift([1,2,3,4],L1), shift(L1,L2), shift(L2,L3).
L1 = [2, 3, 4, 1],
L2 = [3, 4, 1, 2],
L3 = [4, 1, 2, 3].
I created the predicate
conc([],L,L).
conc([X|T],L2,[X|T1]) :-
conc(T,L2,T1).
shift([H|T],L2) :-
conc(T,H,L2).
However, it's wrong & I don't understand why... It works only if the H is surrounded by [H].
shift([H|T],L2) :-
conc(T,[H],L2).
The predicate without the [ ] only works with 1 shift & it outputs the following:
?- shift([1,2,3,4],L1).
L1 = [2, 3, 4|1].
Obviously, there's a basic concept I'm confused with, but I can't seem to pin-point what's wrong alone. I'm new at Prolog, so any help would be appreciated.
It works only if the H is surrounded by [H]
As I noted before, conc/3 is really the standard predicate append/3 which takes in two list and creates a third list.
append/3 says:
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is the concatenation of List1 and List2
A single term is not a list, e.g. 1 is not a list, but [1] is a list.
A list starts with [ and ends with ].
This is the empty list: []
A list can have one item: [a]
or more than one item: [a,b] and so on. Notice how they always have square brackets.
When you use conc/3 or append/3 all three values have to be list, so even if you want to concatenate or append a single item you have to convert it to a list first by surrounding it with [] to turn it into a list. So the single item 1 is converted to a list as [1].

Prolog, permutation code understanding

I'm trying to understand how this program works.
Code from Daniel Lyons' solution(from the link above)
takeout(X,[X|R],R).
takeout(X,[F |R],[F|S]) :- takeout(X,R,S).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
I'm trying ti understand how it works with this list [1,2,3]
So, I have perm([1,2,3],X).
It's easy to understand at first, Y = [2,3] then Y = [3] and then Y = []
After that perm([],[]). is called and it gives us W = []
Now, takeout is called for the first time - takeout(3, Z, []).
It returns Z = [3]
Now, we are going back, where perm([],[]). gives us W = [3], (because Y was [3] at this point)
Same as above, takeout(2, Z, [3]) and Z = [2, 3].
Again perm([], []). and W = [2, 3].
And takeout(1, Z, [2, 3]), which gives us first answer Z = [1, 2, 3]
Here I don't know why program don't end , recursion is done, so why takeout and perm are working again ?
After that takeout is called takeout(1, [2,3]).
Which now works with takeout(X,[F |R],[F|S]) and not with takeout(X,[X|R],R). and that's my second question, why?
In Prolog, a predicate's behavior is quite unlike that of a function in procedural languages. A function is called to perform a task, it executes, and then comes back returning some values or having performed some side effects, or both.
A predicate defines a relation and/or set of facts that establish a logical connection between it's arguments. When a query is made to a predicate in Prolog, Prolog will attempt to find every instantiation of the argument variables that will make that predicate succeed (be true).
In a very simple case, I might have the following facts:
likes(tom, mary). % Tom likes Mary
likes(fred, mary). % Fred likes Mary
Here I have one predicate or fact, likes, which defines a relation between two people. We call the above facts because they each specify a precise, concrete relation with fully instantiated arguments. I can make a query to determine Who likes Mary? as follows:
| ?- likes(Person, mary).
Person = tom ? ;
Person = fred
yes
The query first comes back with Person = tom but indicates it has more options to check once it has found that Person = tom satisfies the query. Entering ; tells Prolog to continue with the next solution (if there is one), and it finds it: Person = fred.
Now let's consider takeout/3. This is a predicate which defines a relation between a set of variables.
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
The takeout/3 predicate has two predicate clauses or rules for the relation. It's helpful to try to read them:
R is what you get if you take X out of [X|R].
[F|S] is what you get if you take X out of [F|R] if S is what you get when you take X out of R.
Prolog looks at multiple clauses in a disjunctive way. That is, a query or call to the predicate will succeed if any one of the rules can hold true. When a query on takeout/3 is made, Prolog will look for instantiations of the given variables in the query which will make it true, and it will attempt to find every such instantiation that does so. In other words, if there's more than one way to satisfy the condition, it will backtrack and attempt to find those variables instantiations that do so.
Consider the query:
?- takeout(X, [1,2,3], R).
Prolog is able to match this to the first predicate clause: takeout(X, [X|R], R) as takeout(1, [1,2,3], [2,3]) by instantiating X = 1 and R = [2,3]. So this query will succeed with the following result:
R = [2,3]
X = 1 ?
But we see that Prolog is indicating there are more options to explore. That's because there's another clause: takeout(X,[F|R],[F|S]) which matches the query, takeout(X, [1,2,3], R). Prolog therefore backtracks and attempts the second clause, which matches:
takeout(X, [1|[2,3]], [1|S]) :- % F = 1, R = [2,3]
takeout(X, [2,3], S).
Prolog will then follow the recursive call takeout(X, [2,3], S) and start from the first clause again and attemp to match takeout(X, [2,3], S) with takeout(X, [X|R], R), which succeeds with X = 2 and S = [3] (takeout(2, [2|[3]], [3]).. The recursion unwinds or returns (as it would in any language), and the previous call head, takeout(X, [1|[2,3]], [1|S]) then ends up instantiating as: takeout(1, [1|[2,3]], [1|[3]]). So we get:
R = [2,3]
X = 1 ? ;
R = [1,3] % that is, [1|[3]]
X = 2 ?
And so on. Similar behavior applies to perm. In the context of the query perm, the calls to takeout backtrack to produce additional results, so perm produces additional results (since its calls to takeout backtrack, just like they do when you query takeout by hand).
As noted by #false, the predicate takeout/3 is implemented as a standard predicate in Prolog as select/3.

Permute into a list SWI-Prolog

How do you use the permute predicate to output into a list in SWI prolog?
The permutation/2 predicate only returns one result at a time.
The most straight forward way to describe all permutations is using bagof/3. Note that findall/3 cannot be used directly, since findall produces literal copies of the original list.
list_allperms(L, Ps) :-
bagof(P, permutation(L,P), Ps).
?- L = [A,B,C], list_allperms(L, Ps).
L = [A, B, C], Ps = [[A,B,C],[A,C,B],[B,A,C],[B,C,A],[C,A,B],[C,B,A]].
So that's the no-brainer version. But you can even implement it directly in pure Prolog without any auxiliary built-ins.
If you want a list of all permutations, findall/3 is the way to go. If you want to print, you can use forall/2. Either case:
case_a(In, L) :- findall(Perm, permutation(In, Perm), L).
case_b(In) :- forall(permutation(In, Perm), writeln(Perm)).
forall it's a general purpose builtin, implementing a failure driven loop, amazing for its' simplicity. I report the definition from SWI-Prolog library, I think it's interesting.
%% forall(+Condition, +Action)
%
% True if Action if true for all variable bindings for which Condition
% if true.
forall(Cond, Action) :-
\+ (Cond, \+ Action).
EDIT:
As noted by false, if you have variables in your list, you should be aware of the different behaviour of findall/3 WRT bagof/3:
?- case_a([1,2,3],X).
X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]].
?- case_a([A,B,C],X).
X = [[_G467, _G470, _G473], [_G455, _G458, _G461], [_G443, _G446, _G449], [_G431, _G434, _G437], [_G419, _G422, _G425], [_G407, _G410, _G413]].
Note that each variable in in the second query output is different: that could be the request outcome, or not, depending on the problem at hand. Deciding the appropriate behaviour WRT the variable quantification is mandatory in the restricted class of problems where variables are data, i.e. metaprogramming, I think...

Prolog permutation extracting solutions

permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
If I type permutation([1,2,3],R), the first solution is "[1,2,3]" but how to get to the second one without using ";" or "fail". I need to use the 2nd solution like "[1,3,2]" or so in order compare it to another list.
What I mean is:
permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
go_perm(L,P) :-
L = P,
write(P),nl.
go_perm(L,P) :-
permutation(P,P2), % in this case i wanna get the next solution -.-
go_perm(L,P2).
If L = P then it finishes. Permutation of the first solution for "[1,2,3]" is "[1,2,3]". But that pulls me into stackoverflow because it runs into never-endless thing.
Perhaps you understand me. Thanks!
Assuming you want to loop over the solutions to print them
One standard way to accomplish this is to fail and backtrack, as in:
print_all_permutations(X)
:- permutation(X, Y), print(Y), nl, fail ; true.
Assuming you just want to check if a given solution is correct
You are already done. Just call the function with the reference list and the list you want to test:
permutation([1, 2, 3], [2, 1, 3]).
will return true, because [2, 1, 3] is a permutation of [1, 2, 3]. If the second argument is not a permutation, the goal will evaluate to false.
This is the magic of prolog: finding a solution, or checking if a given solution is correct, are the same thing.
In between: partial solution
The same reasoning still applies:
permutation([1, 2, 3], [2, X, 3]).
will display the only possible value for X.
Or, if you want the whole list to be the result:
X = [2, X, 3], permutation([1, 2, 3], X).
You need to look at various aggregate predicates. Here, findall would work nicely. you can invoke it:
ListIn=[1,2,3], findall(Perm, permutation(ListIn, Perm), Permutations).
This will call permutation on ListIn until it fails. Each Perm returned by permutation will be collected into the Permutations variable.
permutation is a predicate that succeeds when one list is a permutation of the other. You don't actually need to enumerate them; just write permutation([1, 2, 3], [2, 1, 3]) and Prolog will tell you "true".

Prolog: How to remove every second element of a list

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.