Order of instructions and recursion in Prolog - list

I just started in prolog and I have a question regarding recursion.
I basically want to count the number of time a certain value is in a list,
so I have for example:
count( a, [ a, s, d, f, g, a, s, d, a, s ], W ). W = 3.
Where I want to count the number of time "a" is in the list and store the number in "W".
The correct answer is
count( _, [], 0 ).
count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y + 1.
count( A, [B|S], X ) :- \+ A == B, count( A, S, X ).
Howhever, I do not understand why in line 2, the is a "X is Y+1" at the end.
Shouldn't the line rather be
count( A, [A|S], X ) :- Y is X + 1, count( A, S, Y ).
In that case, we first set Y to 1, then we send it to "count" again with the recursion.
If anyone can help me I'd appreciate it very much!

Consider that when you call:
?- count(a,[a,s,d,f,g,a,s,d,a,s],W).
...then first predicate that matches is count(A,[B|S],X). So that means that it sees it like count(a,[a|S],X) where S & X are variables. X is just W from the original call so it is still a variable.
Suggesting that Y is X + 1 is then evaluated doesn't make sense as X is a variable.
The original predicate, however, does make sense.
count(A,[B|S],X) :- A==B, count(A,S,Y), X is Y + 1.
When it recurses it sends in a new variable Y into the 2nd count/3 predicate (or just passes the same variable in the 3nd predicate). And it keeps doing that until it hits the base case when it finally unifies the variable to 0. At that point it unwinds the recursion and now it can finally do X is Y + 1 (because Y is a value) and hence X is now a value.
Prolog is a fun language because it almost has a sense of time travel in the way you have to think forwards and backwards to understand how a program works.

count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y + 1.
This means: If S contains Y occurrences of A, and A == B, then [B | S] contains one more occurrence of A.
For example, imagine we're getting here while counting the occurrences of prolog in [prolog, prolog, prolog]. [B | S] = [prolog, prolog, prolog], so S = [prolog, prolog]. The number of occurrences of prolog in S is 2, so we should have Y = 2. The number of occurrences of prolog in [B | S] is 3, so we should have X = 3. Once we know Y = 2, then X is Y + 1 computes this correct value of X.
count( A, [A|S], X ) :- Y is X + 1, count( A, S, Y ).
This would mean: If [A | S] contains X occurrences of A, then S contains one more occurrence of A. This cannot be.
Using the above example again: Clearly [A | S] = [prolog, prolog, prolog] contains 3 occurrences of prolog, so X = 3 should hold. But then Y would have to be 4, and the goal in the body would try to prove that S = [prolog, prolog] contains 4 occurrences of prolog. This can clearly not be the case.
Note that this explanation is simply about the meaning of the predicate. It does not require us to think about recursion, or the order of goals, or the exact way that the program is actually executed. When doing Prolog programming, try to be clear about the logical meaning of your programs first.

Related

Comparing lists and elements

I am trying to compare and retrieve values from corresponding lists. My Predicate is correspond_elements(V1, Xs, V2, Ys), where I expect the following behavior:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1;
X = 4.
Where V1 is checked in the first list Xs, and the corresponding values in Ys are given to V2 to return. So far I have this:
% checks if the argument is a list
is_list([]).
is_list([_|T]) :-
is_list(T).
% predicate
correspond_elements(V1, [X|Xs], V2, [Y|Ys]) :-
is_list([X|Xs]),
is_list([Y|Ys]),
( V1 == X ->
V2 is Y
;
correspond_elements(V1, Xs, V2, Ys)
).
Which only gets the first value:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1.
I know that once the -> clause becomes true, then anything after the ; is not executed. It is clear that my code will only get the first answer it finds for X and stop, but I am unsure of how to keep recursing through the list and return all the possible answers for X, even after the first answer has been found.
As you have found out yourself, the if-then-else of Prolog A -> B; C will check the condition A, and if true it will execute B (and not C). Otherwise it will execute C (and not B).
You however want to execute C as an additional option in case A is true. This can be done, by transforming:
foo(Some,Parameters) :-
A
-> B
; C.
into:
foo(Some,Parameters) :-
A,
B.
foo(Some,Parameters) :-
C.
Since now A works as a guard for B, but regardless whether A succeeds or fails, Prolog will backtrack and execute the second foo/2 clause.
If we remove the is_list(..) predicates (which are a bit verbose in my opinion), we can produce the predicate:
correspond_elements(X, [X|_], Y, [Y|_]).
correspond_elements(V1, [_|Xs], V2, [_|Ys]) :-
correspond_elements(V1, Xs, V2, Ys).
We do not have to write the condition V1 == X here, since we used unification in the head for this. Because we use unification, it is V1 = X (one equation sign), so that means we can use the predicate in a more multi-directional way.
Querying the elements in the second list X:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1 ;
X = 4 ;
false.
Querying all tuples A and X of both lists (some sort of "zip"):
?- correspond_elements(A, [a,b,b,a], X, [1,2,3,4]).
A = a,
X = 1 ;
A = b,
X = 2 ;
A = b,
X = 3 ;
A = a,
X = 4 ;
false.
Obtain the elements in the first list:
?- correspond_elements(A, [a,b,b,a], 1, [1,2,3,4]).
A = a ;
false.
Generate a list such that 1 is in the list:
?- correspond_elements(A, [a,b,b,a], 1, L).
A = a,
L = [1|_G1285] ;
A = b,
L = [_G1284, 1|_G1288] ;
A = b,
L = [_G1284, _G1287, 1|_G1291] ;
A = a,
L = [_G1284, _G1287, _G1290, 1|_G1294] .

Swapping a specific number in list 1 with a specific number in list 2

I have been brushing up on some Prolog recently. I kind of enjoy just coming up with random problems to try and solve and then working them out. This one is quite tough though, and I'm not one to give up on a problem that I have set out to solve.
The problem: I want to make a predicate that will have 2 predetermined lists, 2 numbers to swap, and then output the lists after the swapping is done.
Further Explanation: I made it a little harder on myself by wanting to find a specific unique number from list 1, and swapping this with a specific unique number from list 2 so that if I have 2 lists...
[7,2,7,8,5], and [1,2,3,8,7,9,8], and then give the predicate 2 numbers(Lets just say 8 and 7), then the number 8 and the number 7 will be swapped between the lists IF AND ONLY IF the number 8 is in the first list and the number 7 is in the second list. (It would disregard an 8 in the second list and a 7 in the first list).
Sample query with expected answer:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8],8,7,X,Y).
X = [7,2,7,7,5], Y = [1,2,3,8,8,9,8].
I kind of got stuck at this point:
bothSwap([],L2,N1,N2,[],L2).
bothSwap(L1,[],N1,N2,L1,[]).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 == N2, bothSwap(T1,T2,N1,N2,D1,D2), append(D1,[H2],X), append(D2,[H1],Y).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 =\= N2, bothSwap([H1|T1],T2,N1,N2,D1,D2).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 =\= N1, H2 == N2, bothSwap(T1,[H2|T2],N1,N2,D1,D2).
Any bright minds out there willing to tackle this problem with me? :)
Imagine how easy this problem would be if we could just "wish" for a list to be split up at the occurrence of the desired element, like this:
?- splitsies([1,2,3,4,5,6,7,8], 4, Prefix, Suffix).
Prefix = [1, 2, 3],
Suffix = [5, 6, 7, 8] ;
Guess what? :) append/3 can do that:
% splitsies is true if X splits list into a prefix/suffix pair.
splitsies(List, X, Start, Finish) :-
append(Start, [X|Finish], List).
Now the problem seems pretty simple!
bothSwap(Left, Right, A, B, AfterLeft, AfterRight) :-
% break up the inputs
splitsies(Left, A, LPre, LPost),
splitsies(Right, B, RPre, RPost),
% glue together the outputs (note that A and B are switched)
splitsies(AfterLeft, B, LPre, LPost),
splitsies(AfterRight, A, RPre, RPost).
I wouldn't pretend that this solution is efficient… but it's so hot you better wear oven mitts when you type it in. Oh, and check this out:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8], X, Y, [7,2,7,7,5], [1,2,3,8,8,9,8]).
X = 8,
Y = 7 ;
false.
Let's start, what you mean by swapping.
swap(X0,X, S0,S) :-
if_(X0 = S0, S = X, S = S0).
bothSwap0(Xs0, Ys0, X0,X, Xs,Ys) :-
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
if_( C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
Now you wanted a particular condition - it is not clear how to apply it. I see two interpretations:
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
memberd(X0, Xs0),
memberd(X, Ys0),
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
Which means that bothSwap/6 will fail should the two elements not occur in their respective list.
Another interpretation might be that you want that otherwise the lists remain the same. To express this (in a pure monotonic fashion):
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
if_( ( memberd_t(X0, Xs0), memberd_t(X, Ys0) ),
( maplist(swap(X0,X), Xs0,Xs), maplist(swap(X,X0), Ys0,Ys) ),
( Xs0 = Xs, Ys0 = Ys) ).
memberd_t(E, Xs, T) :-
list_memberd(Xs, E, T).
list_memberd([], _, false).
list_memberd([X|Xs], E, T) :-
if_(E = X, T = true, list_memberd(Xs, E, T) ).
','( A_1, B_1, T) :-
if_( A_1, call(B_1, T), T = false ).
Since Prolog is a descriptive language (that is, we describe what constitutes a solution and let Prolog work it out), If I understand your problem statement correctly, something like this ought to suffice:
both_swap(L1, L2, A, B, S1, S2 ) :- % to do the swap,
memberchk(A,L1) , % - L1 must contain an A
memberchk(B,L2) , % - L2 must contain a B
replace(L1,A,B,S1) , % - replace all As in L1 with a B
replace(L2,B,A,S2) % - replace all Bs in L2 with an A
. % Easy!
replace([],_,_,[]) . % if the list is empty, we're done.
replace([H|T],A,B,[S|Ss]) :- % otherwise...
( H = A -> S=B ; S=H ) , % - do the swap (if necessary),
replace(T,A,B,Ss) % - and recurse down
. % Also easy!
This replicates the implementation that uses splitsies/4
swap_two(A,B,C,D,E,F) :-
nth0(I1,A,C,L1),
dif(A,L1),
nth0(I2,B,D,L2),
dif(B,L2),
nth0(I1,E,D,L1),
nth0(I2,F,C,L2).

How to find the Nth element of a list in Prolog

I am trying to write a Prolog code finding the n-th element of a list.
I wrote the below code but it doesn't return the element right.
match([Elem|Tail],Num,Num,Elem).
match([Elem|Tail],Num,C,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
In the first line I say, if the requested element number is equal to counter, then give the first element of the current list to the variable called MatchedNumber. This code returns the Num and Counter right but I don't know why when I want to set the MatchedNumber as Elem, it always returns the first element of the list.
1: what is wrong with this code?
2: How can I say instead of showing the matched number, remove it from list?
First of all, there is a builtin nth0/3 for that:
?- nth0(0,[a,b,c],X).
X = a.
?- nth0(1,[a,b,c],X).
X = b.
?- nth0(2,[a,b,c],X).
X = c.
?- nth0(3,[a,b,c],X).
false.
Get the i-th element
The problem is in the inductive case:
match([Elem|Tail],Num,Counter,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
Prolog doesn't know anything about C so the last statement doens't force Prolog to return the i-th element. It can simply return any element because N will match with Num in the recursive call and then set C to Num+1 but that's not a problem because C is not bound by anything.
A better way to solve this, is using a decrement counter:
match([H|_],0,H) :-
!.
match([_|T],N,H) :-
N > 0, %add for loop prevention
N1 is N-1,
match(T,N1,H).
Example:
?- match([a,b,c,d,e],0,X).
X = a.
?- match([a,b,c,d,e],1,X).
X = b.
?- match([a,b,c,d,e],2,X).
X = c.
?- match([a,b,c,d,e],3,X).
X = d.
?- match([a,b,c,d,e],4,X).
X = e.
?- match([a,b,c,d,e],5,X).
false.
The base case is thus that the index is 0 in which case you return the head, otherwise you query for the i-1-th element of the tail. This is also a more declarative approach.
This approach also makes use of tail recursion which in general will boost performance significantly.
Modifying the original predicate
It is rather un-Prolog to use an iterator and a bound, one in general uses a reverse iterator.
You can however modify the predicate as follows:
match([Elem|_],Num,Num,Elem) :-
!.
match([_|Tail],Num,Count,MatchedNumber) :-
Count < Num,
Count1 is Count+1,
match(Tail,Num,Count1,MatchedNumber).
So a few errors:
Use a "cut" ! in the first clause: since if it matches, we know Prolog should not try the second one;
Use MatchedNumber in the recursive call instead of Elem;
Perform a bound check Count < Num,
Do the increment of the counter Count1 is Count+1 before doing the recursive call; and
Substitute all variables you do not use by underscores _.
An example is then:
?- match([a,b,c,d,e],0,0,X).
X = a.
?- match([a,b,c,d,e],1,0,X).
X = b.
?- match([a,b,c,d,e],2,0,X).
X = c.
?- match([a,b,c,d,e],3,0,X).
X = d.
?- match([a,b,c,d,e],4,0,X).
X = e.
?- match([a,b,c,d,e],5,0,X).
false.
But as said before, it is inefficient to pass an additional argument, etc.
Remove the i-th element from the list
An almost equivalent approach can be used to remove the i-th element from the list:
removei([],_,[]).
removei([_|T],0,T) :-
!.
removei([H|T],N,[H|TR]) :-
N1 is N-1,
removei(T,N1,TR).
Here the base case is again that the index is 0 in which case the tail of the list is removed (thus dropping the head). The inductive case will place the head of the list in the head of the resulting list and will count on the recursive call to remove the correct item from the tail. Another base case removei([],_,[]). is added because it is possible that i is greater than the length of the list in which case this predicate won't remove any item.
Example
?- removei([a,b,c,d,e],0,X).
X = [b, c, d, e].
?- removei([a,b,c,d,e],1,X).
X = [a, c, d, e].
?- removei([a,b,c,d,e],2,X).
X = [a, b, d, e].
?- removei([a,b,c,d,e],3,X).
X = [a, b, c, e].
?- removei([a,b,c,d,e],4,X).
X = [a, b, c, d].
?- removei([a,b,c,d,e],5,X).
X = [a, b, c, d, e].
?- removei([a,b,c,d,e],6,X).
X = [a, b, c, d, e].
To find the nth element of a list (where n is relative to zero), something like this ought to suffice:
find_nth_element_of_list( 0 , X , [X|_] ) .
find_nth_element_of_list( N , X , [_|Xs] ) :-
N > 0 ,
N1 is N-1 ,
find_nth_element_of_list( N1 , X , Xs )
.
Similarly, to remove the nth element of a list, something like this ought to suffice:
remove_nth_element_of_list( 0 , [_|Xs] , Xs ) . % at n=0, toss the head and unify the tail with the result set
remove_nth_element_of_list( N , [X|Xs] , [X|Ys] ) :- % at n>0, prepend the head to the result and recurse down.
N > 0 ,
N1 is N-1 ,
remove_nth_element_of_list( N1 , Xs , Ys )
.
If for some reason you need to achieve this using no built-in predicates besides append here is my implementation:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, List, H) :-
append(L1, [H|_], List),
my_length(L1, N),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
and without append:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(0, [H|_], H) :- !.
my_nth(N, [_|T], Result) :-
N1 is N - 1,
my_nth(N1, T, Result),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
And without !:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, [_|T], Result) :-
N > 0,
N1 is N - 1,
my_nth(N1, T, Result).
my_nth(0, [H|_], H).
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
Why would anyone need it? There is a specific professor at Poznan University of Technology that requires students to write predicates like this.

Prolog Programming List Arithmetic

Here is my code to make a countdown procedure which when I type in countdown(5,L). should return
L = [5,4,3,2,1] and countdown(5,[5,4,3,2,1]) should return true.
The input countdown(5,L). returns
ERROR: is/2: Type error: []' expected, found[5,4]' ("x" must hold one character)
which shows me my program is beginning to create the list.
%countdown
countdown(1,[1]).
countdown(A,L) :-
concat([],[A],Z),
makeList(Z,A,List),
L is List.
makeList(X,Y,List) :-
N1 is Y-1,
N1 > 0,
concat(X,[N1],Z),
List is Z,
makeList(Z,N1,List).
concat([],Y,Y).
concat([H|X],Y,[H|Z]):-
concat(X,Y,Z).
Why so difficult?
countdown(1, [1]).
countdown(N, [N|T]) :-
N1 is N-1,
countdown(N1, T).
Some comments on your code:
countdown/2, clause 2, line 1:
concat([],[A],Z) is completely unnecessary.
At the end of this exercise, Z is unified with [A].
countdown/2, clause 2, line 3:**
As was pointed out, is/2 evaluates the right hand term as an
arithmetic expression and unifies the result with the left-hand side.
This should be L = List.
Even better, just change the line above from makeList(Z,A,List) to makeList(Z,A,L).
But this is overly complicated. If one was to take your general approach, you could do it thusly:
count_down(N,L) :- % To count down to 1 from N,
integer(N) , % N must first be integral
N > 0 , % and positive
range(N,1,L). % Then you just need to generate the desired range.
range/3 could be implemented simply as this:
range( X , Y , [X] ) :- X = Y .
range( X , Y , [X|Xs] ) :- X > Y , X1 is X-1 , range(X1,Y,Xs) .
range( X , Y , [X|Xs] ) :- X < Y , X1 is X+1 , range(X1,Y,Xs) .

Count only numbers in list of numbers and letters

I'm new to Prolog and I can't seem to get the answer to this on my own.
What I want is, that Prolog counts ever Number in a list, NOT every element. So for example:
getnumbers([1, 2, c, h, 4], X).
Should give me:
X=3
getnumbers([], 0).
getnumbers([_ | T], N) :- getnumbers(T, N1), N is N1+1.
Is what I've got, but it obviously gives me every element in a list. I don't know how and where to put a "only count numbers".
As usual, when you work with lists (and SWI-Prolog), you can use module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
:- use_module(library(lambda)).
getnumbers(L, N) :-
foldl(\X^Y^Z^(number(X)
-> Z is Y+1
; Z = Y),
L, 0, N).
Consider using the built-in predicates (for example in SWI-Prolog), and checking their implementations if you are interested in how to do it yourself:
include(number, List, Ns), length(Ns, N)
Stay logically pure, it's easy: Use the meta-predicate
tcount/3 in tandem with the reified type test predicate number_t/2 (short for number_truth/2):
number_t(X,Truth) :- number(X), !, Truth = true.
number_t(X,Truth) :- nonvar(X), !, Truth = false.
number_t(X,true) :- freeze(X, number(X)).
number_t(X,false) :- freeze(X,\+number(X)).
Let's run the query the OP suggested:
?- tcount(number_t,[1,2,c,h,4],N).
N = 3. % succeeds deterministically
Note that this is monotone: delaying variable binding is always logically sound. Consider:
?- tcount(number_t,[A,B,C,D,E],N), A=1, B=2, C=c, D=h, E=4.
N = 3, A = 1, B = 2, C = c, D = h, E = 4 ; % succeeds, but leaves choice point
false.
At last, let us peek at some of the answers of the following quite general query:
?- tcount(number_t,[A,B,C],N).
N = 3, freeze(A, number(A)), freeze(B, number(B)), freeze(C, number(C)) ;
N = 2, freeze(A, number(A)), freeze(B, number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A, number(A)), freeze(B,\+number(B)), freeze(C, number(C)) ;
N = 1, freeze(A, number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)) ;
N = 2, freeze(A,\+number(A)), freeze(B, number(B)), freeze(C, number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B, number(B)), freeze(C,\+number(C)) ;
N = 1, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C, number(C)) ;
N = 0, freeze(A,\+number(A)), freeze(B,\+number(B)), freeze(C,\+number(C)).
of course, you must check the type of an element to see if it satisfies the condition.
number/1 it's the predicate you're looking for.
See also if/then/else construct, to use in the recursive clause.
This uses Prolog's natural pattern matching with number/1, and an additional clause (3 below) to handle cases that are not numbers.
% 1 - base recursion
getnumbers([], 0).
% 2 - will pass ONLY if H is a number
getnumbers([H | T], N) :-
number(H),
getnumbers(T, N1),
N is N1+1.
% 3 - if got here, H CANNOT be a number, ignore head, N is unchanged, recurse tail
getnumbers([_ | T], N) :-
getnumbers(T, N).
A common prolog idiom with this sort of problem is to first define your predicate for public consumption, and have it invoke a 'worker' predicate. Often it will use some sort of accumulator. For your problem, the public consumption predicate is something like:
count_numbers( Xs , N ) :-
count_numbers_in_list( Xs , 0 , N ) .
count_numbers_in_list( [] , N , N ) .
count_numbers_in_list( [X|Xs] , T , N ) :-
number(X) ,
T1 is T+1 ,
count_numbers_in_list( Xs , T1 , N )
.
You'll want to structure the recursive bit so that it is tail recursive as well, meaning that the recursive call depends on nothing but data in the argument list. This allows the compiler to reuse the existing stack frame on each call, so the predicate becomes, in effect, iterative instead of recursive. A properly tail-recursive predicate can process a list of infinite length; one that is not will allocate a new stack frame on every recursion and eventually blow its stack. The above count_numbers_in_list/3 is tail recursive. This is not:
getnumbers([H | T], N) :-
number(H),
getnumbers(T, N1),
N is N1+1.