What does this code mean and do? - list

I am completely new to Prolog and I can't understand this piece of code. How would you read these 4 clauses? What do they do?
a([]).
a([_|L]):-b(L).
b([_]).
b([_|L]):-a(L).
Thank you.

As #repeat suggested in his comment, run a general query, and here's what you get:
| ?- a(Xs).
Xs = [] ? ;
Xs = [_,_] ? ;
Xs = [_,_] ? ;
Xs = [_,_,_,_] ? ;
Xs = [_,_,_,_] ? ;
Xs = [_,_,_,_,_,_] ? ;
Xs = [_,_,_,_,_,_] ? ;
...
And:
| ?- b(Xs).
Xs = [_] ? ;
Xs = [_] ? ;
Xs = [_,_,_] ? ;
Xs = [_,_,_] ? ;
Xs = [_,_,_,_,_] ? ;
Xs = [_,_,_,_,_] ? ;
Xs = [_,_,_,_,_,_,_] ? ;
Xs = [_,_,_,_,_,_,_] ? ;
...
So a(Xs) succeeds if Xs is a list containing an even number of elements, and b(Xs) succeeds if Xs is a list containing an odd number of arguments. As you can see, a/1 and b/1 succeed twice in each case except a([]). which succeeds only once. So it is not an efficient predicate for determining list length parity.
Let's rewrite these with more descriptive names:
even([]).
even([_|L]) :- odd(L).
odd([_]).
odd([_|L]) :- even(L).
Now let's "read" what they say:
[] is an even list
[_|L] is an even list if L is an odd list
[_] is an odd list
[_|L] is an odd list if L is an even list
These sound logical, but why do even/1 and odd/1 succeed twice with the exception of even([])? If you look at the definition of odd/1, there are two ways for [_] to succeed. One is via the odd([_]). clause. The second is by the second odd/1, since you would have:
odd([_|[]]) :- even([]). % [_] == [_|[]]
Since both even/1 and odd/1 calls (with the exception of even([]).) eventually recurse down to a call to odd([_]), you'll get two solutions.
One way to eliminate the ambiguity in the logic is to refactor them a little. Consider the following recursive rules:
A list of at least 2 elements has an even number of elements if the tail of the list, after the first 2, is also even.
A list of at least 2 elements has an odd number of elements if the tail of the list, after the first 2, is also odd.
Translating these rules to Prolog, including the base cases as before:
even([]).
even([_,_|L]) :- even(L).
odd([_]).
odd([_,_|L]) :- odd(L).
Now the results will be:
| ?- even(Xs).
Xs = [] ? ;
Xs = [_,_] ? ;
Xs = [_,_,_,_] ? ;
Xs = [_,_,_,_,_,_] ? ;
...
And
| ?- odd(Xs).
Xs = [_] ? ;
Xs = [_,_,_] ? ;
Xs = [_,_,_,_,_] ? ;
...
Following CapelliC's suggestion of using a DCG, similar rules can be written:
even --> [] | [_,_], even.
odd --> [_] | [_,_], odd.
With results:
| ?- phrase(even, L).
L = [] ? ;
L = [_,_] ? ;
L = [_,_,_,_] ? ;
...
And
| ?- phrase(odd, L).
L = [_] ? ;
L = [_,_,_] ? ;
L = [_,_,_,_,_] ? ;
...
Following #false's suggestion, an even more direct "fix" to the original code would be to eliminate the redundant base case for odd([_]). since it's already covered by the base case for even([]). This is also a little simpler than the above solution since it takes advantage of the interdependency between the even/1 and odd/1 predicates (in the above solution, even/1 and odd/1 stand on their own).
even([]).
even([_|L]) :- odd(L).
odd([_|L]) :- even(L).
Or, in DCG:
even --> [] | [_], odd.
odd --> [_], even.

the argument schema is important:
a) the list is clearly a counter, since we never consider the content.
b) just a suggestion: read logic as productions, or as DCG
a-->[];[_],b.
b-->[_];[_],a.
to be called - for instance
?- phrase(a, [w,h,a,t]).

Related

How to get all consecutive sublists/subsets in Prolog?

I would like to solve a simple problem, but even through I tried many different approaches, I couldn't find a solution for it. I am using SICStus Prolog (if that matters), and I want to get all sublists/subsets (I don't know which term is correct for this) of a list, which contains elements in succession. For example, if I have the list [1, 2, 3, 4], calling the sl/2 predicate as sl([1, 2, 3, 4], R)., the expected result is:
? - sl([1, 2, 3, 4], R).
R = [] ? ;
R = [1] ? ;
R = [1, 2] ? ;
R = [1, 2, 3] ? ;
R = [1, 2, 3, 4] ? ;
R = [2] ? ;
R = [2, 3] ? ;
R = [2, 3, 4] ? ;
R = [3] ? ;
R = [3, 4] ? ;
R = [4] ? ;
no
The best result I could reach until now is:
sl([], []).
sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
sl([_|Xs], Ys) :-
sl(Xs, Ys).
But this also gives me the following unwanted results in addition:
R = [1,2,4] ? ;
R = [1,3,4] ? ;
R = [1,3] ? ;
R = [1,4] ? ;
R = [2,4] ? ;
How should I modify my predicates so I can get the desired result?
When writing a predicate in Prolog, you need to think about what the predicate means, or what relation it is defining. The reason your predicate gives non-solutions is that you are mixing meanings in your predicate clauses. They don't all really mean the same thing.
You have the predicate sl/2 which is intended to mean "sublist" (or "subsequence") but, more than that, means a sublist per the description you provided, which is a contiguous sublist (cannot have any "gaps" in it).
Now we can break down your clauses:
sl([], []).
This says the empty list is a contiguous sublist of the empty list. This is true, so is a valid fact.
sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
This says that [X|Ys] is a contiguous sublist of [X|Xs] if Ys is a contiguous sublist of Xs. This relation is not true. What would really be true here would be: [X|Ys] is a contiguous sublist of [X|Xs] if Ys is a contiguous prefix sublist of Xs. That is, not only does Ys need to be a sublist of Xs, but it needs to be only from the start of the list and not somewhere within this list. This is a clue that you'll need another predicate since the meaning of the relation is different.
Your final clause says that Ys is a sublist of [_|Xs] if Ys is a sublist of Xs. This appears to be true.
If we simply adjust to the above updated definitions, we get:
subseq([], []).
subseq([_|Xs], Ys) :-
subseq(Xs, Ys).
subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
prefix_subseq(_, []).
prefix_subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
I offered the prefix_subseq/2 definition above without explanation, but I think you can figure it out.
This now yields:
| ?- subseq([a,b,c,d], R).
R = [a] ? a
R = [a,b]
R = [a,b,c]
R = [a,b,c,d]
R = [b]
R = [b,c]
R = [b,c,d]
R = [c]
R = [c,d]
R = [d]
R = []
(1 ms) yes
An interesting, compact way of defining your sublist (or subsequence) would be using the append/2 predicate:
subseq(L, R) :- append([_, R, _], L).
This says that L is the result of appending lists _, R, and _. The minor flaw in this simple implementation is that you'll get R = [] more than once since it satisfies the append([_, R, _], L) rule in more than one way.
Taking a fresh look at the definition, you can use a DCG to define a subsequence, as a DCG is perfect for dealing with sequences:
% Empty list is a valid subsequence
subseq([]) --> ... .
% Subsequence is any sequence, followed by sequence we want, followed by any sequence
subseq(S) --> ..., non_empty_seq(S), ... .
% Definition of any sequence
... --> [] | [_], ... .
% non-empty sequence we want to capture
non_empty_seq([X]) --> [X].
non_empty_seq([X|T]) --> [X], non_empty_seq(T).
And you can call it with phrase/2:
| ?- phrase(subseq(S), [a,b,c,d]).
S = [] ? ;
S = [a] ? ;
S = [a,b] ? ;
S = [a,b,c] ? ;
S = [a,b,c,d] ? ;
S = [b] ? ;
S = [b,c] ? ;
S = [b,c,d] ? ;
S = [c] ? ;
S = [c,d] ? ;
S = [d] ? ;
no
We can reswizzle this definition a little and make use of a common seq//1 definition to make it more compact:
subseq([]) --> seq(_) .
subseq([X|Xs]) --> seq(_), [X], seq(Xs), seq(_).
% alternatively: seq(_), seq([X|Xs]), seq(_).
seq([]) --> [].
seq([X|Xs]) --> [X], seq(Xs).

How can I compare two lists in prolog, returning true if the second list is made of every other element of list one?

I would solve it by comparing the first index of the first list and adding 2 to the index. But I do not know how to check for indexes in prolog.
Also, I would create a counter that ignores what is in the list when the counter is an odd number (if we start to count from 0).
Can you help me?
Example:
everyOther([1,2,3,4,5],[1,3,5]) is true, but everyOther([1,2,3,4,5],[1,2,3]) is not.
We present three logically-pure definitions even though you only need one—variatio delectat:)
Two mutually recursive predicates list_oddies/2 and skipHead_oddies/2:
list_oddies([],[]).
list_oddies([X|Xs],[X|Ys]) :-
skipHead_oddies(Xs,Ys).
skipHead_oddies([],[]).
skipHead_oddies([_|Xs],Ys) :-
list_oddies(Xs,Ys).
The recursive list_oddies/2 and the non-recursive list_headless/2:
list_oddies([],[]).
list_oddies([X|Xs0],[X|Ys]) :-
list_headless(Xs0,Xs),
list_oddies(Xs,Ys).
list_headless([],[]).
list_headless([_|Xs],Xs).
A "one-liner" which uses meta-predicate foldl/4 in combination with Prolog lambdas:
:- use_module(library(lambda)).
list_oddies(As,Bs) :-
foldl(\X^(I-L)^(J-R)^(J is -I,( J < 0 -> L = [X|R] ; L = R )),As,1-Bs,_-[]).
All three implementations avoid the creation of useless choicepoints, but they do it differently:
#1 and #2 use first-argument indexing.
#3 uses (->)/2 and (;)/2 in a logically safe way—using (<)/2 as the condition.
Let's have a look at the queries #WouterBeek gave in his answer!
?- list_oddies([],[]),
list_oddies([a],[a]),
list_oddies([a,b],[a]),
list_oddies([a,b,c],[a,c]),
list_oddies([a,b,c,d],[a,c]),
list_oddies([a,b,c,d,e],[a,c,e]),
list_oddies([a,b,c,d,e,f],[a,c,e]),
list_oddies([a,b,c,d,e,f,g],[a,c,e,g]),
list_oddies([a,b,c,d,e,f,g,h],[a,c,e,g]).
true. % all succeed deterministically
Thanks to logical-purity, we get logically sound answers—even with the most general query:
?- list_oddies(Xs,Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_B], Ys = [_A]
; Xs = [_A,_B,_C], Ys = [_A,_C]
; Xs = [_A,_B,_C,_D], Ys = [_A,_C]
; Xs = [_A,_B,_C,_D,_E], Ys = [_A,_C,_E]
; Xs = [_A,_B,_C,_D,_E,_F], Ys = [_A,_C,_E]
; Xs = [_A,_B,_C,_D,_E,_F,_G], Ys = [_A,_C,_E,_G]
; Xs = [_A,_B,_C,_D,_E,_F,_G,_H], Ys = [_A,_C,_E,_G]
...
There are two base cases and one recursive case:
From an empty list you cannot take any odd elements.
From a list of length 1 the only element it contains is an odd element.
For lists of length >2 we take the first element but not the second one; the rest of the list is handled in recursion.
The code looks as follows:
odd_ones([], []).
odd_ones([X], [X]):- !.
odd_ones([X,_|T1], [X|T2]):-
odd_ones(T1, T2).
Notice that in Prolog we do not need to maintain an explicit index that has to be incremented etc. We simply use matching: [] matches the empty list, [X] matches a singleton list, and [X,_|T] matches a list of length >2. The | separates the first two elements in the list from the rest of the list (called the "tail" of the list). _ denotes an unnamed variable; we are not interested in even elements.
Also notice the cut (!) which removes the idle choicepoint for the second base case.
Example of use:
?- odd_ones([], X).
X = [].
?- odd_ones([a], X).
X = [a].
?- odd_ones([a,b], X).
X = [a].
?- odd_ones([a,b,c], X).
X = [a, c].
?- odd_ones([a,b,c,d], X).
X = [a, c].
?- odd_ones([a,b,c,d,e], X).
X = [a, c, e].

List as variable/argument in Prolog

I've created a function in Prolog to "turn" a list, e.g. to append the head of a list to the tail like so:
?- turn([a,b,c,d,e], Tlist).
Tlist=[b,c,d,e,a]
Within the context of my program, I'd like to be able to use predefined lists for the rule, such as
alist([a,b,c,d,e,f])
but I get lots of different errors. I've tried the following as arguments:
turn(alist(L),R).
listv(X) :- alist(L), member(X, L).
turn(listv(X),R).
and I understand that each of these are different representations of the list according to Prolog, but I'm not sure which list representation is appropriate to complete the operation on a predefined list.
Thanks!
The predicate turn/2 can easily be defined based on append/3:
turn([A|As],Bs) :-
append(As,[A],Bs).
For specifying some sample lists, we define an auxiliary predicate named_list/2:
named_list(one_to_nine , [1,2,3,4,5,6,7,8,9]).
named_list(a_to_f , [a,b,c,d,e,f]).
named_list(single_digit_primes, [2,3,5,7]).
Let's query!
?- named_list(a_to_f,Xs), turn(Xs,Ys).
Xs = [a,b,c,d,e,f], Ys = [b,c,d,e,f,a]. % succeeds deterministically
?- named_list(a_to_f,Ys), turn(Xs,Ys). % "other" direction
Ys = [a,b,c,d,e,f], Xs = [f,a,b,c,d,e] % succeeds leaving behind choicepoint
; false.
So far, we have used one specific sample list a_to_f in the queries; let's use 'em all!
?- named_list(Name,Xs), turn(Xs,Ys).
Name = one_to_nine , Xs = [1,2,3,4,5,6,7,8,9], Ys = [2,3,4,5,6,7,8,9,1]
; Name = a_to_f , Xs = [a,b,c,d,e,f] , Ys = [b,c,d,e,f,a]
; Name = single_digit_primes, Xs = [2,3,5,7] , Ys = [3,5,7,2].

I would like to check in prolog if one list has the same elements

I would like to write in prolog "check if one list has the same elements" e.g list[a,a,a,a] is true. list[a,c,a,a] is false.
How can I do so?
It can be done with one, simple predicate:
same([]). % You only need this one if you want the empty list to succeed
same([_]).
same([X,X|T]) :- same([X|T]).
Results:
| ?- same([a,b,a,a]).
no
| ?- same([a,a,a,a]).
true ? ;
no
| ?- same([]).
yes
ADDENDUM 1
Changing the order of the clauses so that the base cases are first allows:
| ?- same(L).
L = [] ? ;
L = [_] ? ;
L = [A,A] ? ;
L = [A,A,A] ? ;
...
ADDENDUM 2
Another approach, using DCG, might be:
same(_) --> [].
same(X) --> [X], same(X).
Then:
| ?- phrase(same(_), [a,b,a,a]).
no
| ?- phrase(same(_), [a,a,a,a]).
true ? a
(1 ms) no
| ?- phrase(same(X), L).
L = [] ? ;
L = [X] ? ;
L = [X,X] ? ;
L = [X,X,X] ? ;
...
same(L) :-
maplist(=(_),L).
?- maplist(=(_),L).
L = []
; L = [_A]
; L = [_A,_A]
; L = [_A,_A,_A]
; L = [_A,_A,_A,_A]
; L = [_A,_A,_A,_A,_A]
; L = [_A,_A,_A,_A,_A,_A]
; ... .
See also this answer.
Okay, now that I understood the request whats about this:
compare([X|Y]):-help(Y,X).
compare([]).
help([],_).
help([Y|X],Y) :- help(X,Y).
Using the built-in list_to_set/2, this can be done in a single line:
?- list_to_set([a,a,a,a],[_]).
true.
?- list_to_set([a,a,c,a],[_]).
false.
The conversion of a list to a set removes duplicates.. so if you are left with a list that can be unified to one item [_], then there are no duplicates.
If the list has duplicates, there will be > 1 item in the set, and the [_] predicate unification will fail.
This obviously won't work on an empty list - a separate rule will be needed for that.

Even sized list in Prolog

I've been trying to write a predicate which would evaluate the size of a list to be even or not and this has to be done without computing the length of the list or any arithmetic operations. It's supposedly easier than computing the length but I'm having trouble thinking of how to do it without that. I'm guessing a sort of recursive technique but if anyone is able to help it would be great.
Yes, you want recursion. The base cases would be the smallest odd/even lists you can have, and then all you need is to figure out how to construct the recursive call so that it will boil down to the base case. You could start out by imagining a list of length 3 that's supposed to return true for "oddList". If it's not the base case, what's the next logical step? How does an odd list differ from an even one?
Preserve logical-purity! Simply proceed like this:
evenlength([]). % smallest list with even length is [] (length=0)
evenlength([_|Xs]) :-
oddlength(Xs).
oddlength([_|Xs]) :- % smallest list with odd length is [_] (length=1)
evenlength(Xs).
Some simple ground queries for evenlength/1 and oddlength/1:
?- evenlength([]).
true.
?- oddlength([]).
false.
?- evenlength([1]).
false.
?- oddlength([1]).
true.
?- evenlength([1,2]).
true.
?- oddlength([1,2]).
false.
?- evenlength([1,2,3]).
false.
?- oddlength([1,2,3]).
true.
Note that these predicates can not only test candidate lists, but also generate them:
?- evenlength(Xs).
Xs = []
; Xs = [_A,_B]
; Xs = [_A,_B,_C,_D]
; Xs = [_A,_B,_C,_D,_E,_F]
...
?- oddlength(Xs).
Xs = [_A]
; Xs = [_A,_B,_C]
; Xs = [_A,_B,_C,_D,_E]
; Xs = [_A,_B,_C,_D,_E,_F,_G]
...
Using meta-predicate foldl/4 and Prolog lambdas all we need to do is:
evenlength(Xs) :-
foldl(\_^E^O^(O is \E),Xs,1,1). % each item in `Xs` flips the "evenness flag"
Sample uses:
?- evenlength([]).
true.
?- evenlength([_]).
false.
?- evenlength([_,_]).
true.
?- evenlength([_,_,_]).
false.
?- evenlength([_,_,_,_]).
true.
Let's not forget about the most general query!
?- evenlength(Xs).
Xs = []
; Xs = [_A,_B]
; Xs = [_A,_B,_C,_D]
; Xs = [_A,_B,_C,_D,_E,_F]
...
I know it is too late to answer your question, but hopefully this will help:
To find list has odd length:
oddlength([_]).
oddlength([_,_|R]) :- oddlength(R),!.
To find list has even length:
evenlength([]).
evenlength([_,_|R]) :- evenlength(R),!.