I want to find the bigger value from a list's element's pairs.
Ie. list=[5,7,4,5,6,8] the pairs are [5,7], [7,4], [4,5] etc.
Right now I have this little code snippet:
bigger([],X).
bigger([E1],[H|E1]).
bigger([E1,E2|T],[H|_]):-
(E1>E2,bigger([E2|T],[H|E1]));
(E1<E2,bigger([E2|T],[H|E2])).
The solution should look like:
?- bigger([5,7,4,5,6,8],X).
X = [7,7,5,6,8,8]
EDIT:
Deleted the remove/3 lines, since they're wrong.
I'll give MY understanding of how the code works.
Empty given list check.
One element list check, adds it to output list end ([H|E1])
More than one element in given list, output list
3.1 First two element check (E1 >/< E2)
3.2 New recursive query without E1 (first element)
3.3 Whichever is bigger is output list's last element now.
First I'll show you my solution of your problem (and the result shouldn't be X = [7,7,5,6,8]? I'll make this version.)
gtr(X,Y,Y) :-
Y>=X.
gtr(X,_,X).
bigger([],[]).
bigger([_], []).
bigger([X,Y|R], [Z|H]) :-
bigger([Y|R],H), gtr(X,Y,Z),!.
If you want to have last element appear in this list anyway than just change second bigger function.
Since the relation is describing lists you could opt to use DCGs for the task:
max_of(X,X,Y) :- X >= Y. % X is maximum if X>=Y
max_of(Y,X,Y) :- Y > X. % Y is maximum if Y>X
list_biggers(L,B) :-
phrase(biggers(L),B). % the DCG biggers//1 describes B based on L
biggers([]) --> % if the list is empty
[]. % there's no element in the biggers list
biggers([X]) --> % if the list contains just one element
[X]. % it is in the biggers list
biggers([X,Y|Xs]) --> % if the list contains at least two elements
{max_of(M,X,Y)}, % the maximum of them
[M], % is in the biggers list
biggers([Y|Xs]). % the same holds for [Y|Xs]
This definition is sticking to your reading of the task, that is, in the case of a one-element list the only element is in the list of bigger elements:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8, 8] ;
false.
?- list_biggers([1],B).
B = [1] ;
false.
If you prefer the reading suggested by #Armatorix, just change the second DCG-rule to
biggers([_X]) -->
[].
This way the queries above yields the following results:
?- list_biggers([5,7,4,5,6,8],B).
B = [7, 7, 5, 6, 8] ;
false.
?- list_biggers([1],B).
B = [] ;
false.
Note that the list has to be sufficiently instantiated. Otherwise you get an error:
?- list_biggers([X,Y,Z],B).
ERROR: >=/2: Arguments are not sufficiently instantiated
If the list only contains integers, you can remedy this problem by using CLP(FD). Add a line to include the library and change max_of/2 like so:
:- use_module(library(clpfd)).
max_of(X,X,Y) :- X #>= Y.
max_of(Y,X,Y) :- Y #> X.
Now the query above delivers all 4 expected solutions:
?- list_biggers([X,Y,Z],B).
B = [X, Y, Z],
X#>=Y,
Y#>=Z ;
B = [X, Z, Z],
X#>=Y,
Y#=<Z+ -1 ;
B = [Y, Y, Z],
X#=<Y+ -1,
Y#>=Z ;
B = [Y, Z, Z],
X#=<Y+ -1,
Y#=<Z+ -1 ;
false.
In order to construct logical programs, one needs to think logical. Based on the problem statement, there are three possibilities here:
we have an empty list, in that case the result is an empty list as well:
bigger([],[]).
in case we have a list with one element, the problem is underspecified. I would say that the result should be an empty list, but your example seems to suggest that we return that number, since we then have a 1-tuple, and the maximum of a 1-tuple is of course the single element in the tuple:
bigger([H],[H]).
in case the list contains two or more elements [H1,H2|T], then H1 and H2 are the first two elements. In that case we construct a vitual tuple in our head [H1,H2] and calculate the maximum, which is thus M is max(H1,H2). We prepend M to the resulting list of the recursion. That recursion is done on the list [H2|T]: the list where we popped H1 from:
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger([H2|T],U).
Or putting this all together:
bigger([],[]).
bigger([H],[H]).
bigger([H1,H2|T],[M|U]) :-
M is max(H1,H2),
bigger(T,U).
Related
New to prolog and trying to implement the following function that takes 3 lists:
True if lists are the same length
True if elements of third list is sum of the two lists
Example: fn([1,2,3],[4,5,6],[5,7,9]) returns true. Note that the sum is element-wise addition.
This is what I have so far:
fn([],[],[]).
fn([_|T1], [_|T2], [_|T3]) :-
fn(T1,T2,T3), % check they are same length
fn(T1,T2,N1), % check that T3=T1+T2
N1 is T1+T2,
N1 = T3.
From what I understand, the error is due to the base case (it has empty lists which causes error with evaluation of addition?)
Thanks for any help and explanations!
In addition to #GuyCoder's answer, I would point out that it is worthwhile to consider using one of the maplist predicates from library(apply) when modifying all elements of lists. You can use a predicate to describe the relation between three numbers...
:- use_module(library(apply)). % for maplist/4
num_num_sum(X,Y,S) :-
S is X+Y.
... and subsequently use maplist/4 to apply it to entire lists:
fn(X,Y,Z) :-
maplist(num_num_sum,X,Y,Z).
This predicate yields the desired results if the first two lists are fully instantiated:
?- fn([1,2,3],[4,5,6],X).
X = [5,7,9]
However, due to the use of is/2 you get instantiation errors if the first two lists contain variables:
?- fn([1,A,3],[4,5,6],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is _+B: expected bound value
?- fn([1,2,3],[4,5,A],[5,7,9]).
ERROR at clause 1 of user:num_num_sum/3 !!
INSTANTIATION ERROR- X is A+B: expected bound value
If you only want to use the predicate for lists of integers, you can use CLP(FD) to make it more versatile:
:- use_module(library(apply)).
:- use_module(library(clpfd)). % <- use CLP(FD)
int_int_sum(X,Y,S) :-
S #= X+Y. % use CLP(FD) constraint #=/2 instead of is/2
fnCLP(X,Y,Z) :-
maplist(int_int_sum,X,Y,Z).
With this definition the previously problematic queries work as well:
?- fnCLP([1,A,3],[4,5,6],[5,7,9]).
A = 2
?- fnCLP([1,2,3],[4,5,A],[5,7,9]).
A = 6
Even the most general query yields results with this version:
?- fnCLP(X,Y,Z).
X = Y = Z = [] ? ;
X = [_A],
Y = [_B],
Z = [_C],
_A+_B#=_C ? ;
X = [_A,_B],
Y = [_C,_D],
Z = [_E,_F],
_A+_C#=_E,
_B+_D#=_F ? ;
.
.
.
Since the numbers in the above answers are not uniquely determined, you get residual goals instead of actual numbers. In order to get actual numbers in the answers, you have to restrict the range of two of the lists and label them subsequently (see documentation for details), e.g. to generate lists containing the numbers 3,4,5 in the first list and 6,7,8 in the second list, you can query:
label the lists
restrict the domain | |
v v v v
?- fnCLP(X,Y,Z), X ins 3..5, Y ins 6..8, label(X), label(Y).
X = Y = Z = [] ? ;
X = [3],
Y = [6],
Z = [9] ? ;
X = [3],
Y = [7],
Z = [10] ? ;
.
.
.
X = [3,4],
Y = [6,7],
Z = [9,11] ? ;
X = [3,4],
Y = [6,8],
Z = [9,12] ? ;
.
.
.
On an additional note: there are also clp libraries for booleans (CLP(B)), rationals and reals (CLP(Q,R)) that you might find interesting.
From what I understand, the error is due to the base case.
I don't see it that way.
The first problem I see is that you are trying to process list which leads to thinking about using DCGs, but since you are new I will avoid that route.
When processing list you typically process the head of the list then pass the tail back to the predicate using recursion.
e.g. for length of list you would have
ln([],N,N).
ln([_|T],N0,N) :-
N1 is N0+1,
ln(T,N1,N).
ln(L,N) :-
ln(L,0,N).
The predicate ln/2 is used to set up the initial count of 0 and the predicate ln/3 does the work using recursion. Notice how the head of the list is taken off the front of the list and the tail of the list is passed recursively onto the predicate again. When the list is empty the predicate ln([],N,N). unifies, in this case think copies, the intermediate count from the second position into the third position, which it what is passed back with ln/2.
Now back to your problem.
The base case is fine
fn([],[],[]).
There are three list and for each one look at the list as [H|T]
fn([H1|T1],[H2|T2],[H3|T3])
and the call to do the recursion on the tail is
fn(T1,T2,T3)
all that is left is to process the heads which is
H3 is H1 + H2
putting it all together gives us
fn([],[],[]).
fn([H1|T1], [H2|T2], [H3|T3]) :-
H3 is H1 + H2,
fn(T1,T2,T3).
and a quick few checks.
?- fn([],[],[]).
true.
?- fn([1],[1],[2]).
true.
?- fn([1,2],[3,4],[4,6]).
true.
?- fn([1,2],[3,4,5],[4,6,5]).
false.
With regards to the two conditions. When I look at exercises problems for logic programming they sometimes give a condition like True if lists are the same length or some other condition that returns true. I tend to ignore those at first and concentrate on getting the other part done first, in this case elements of third list is sum of the two lists then I check to see if the other conditions are correct. For most simple classroom exercises they are. I sometimes think teacher try to give out these extra conditions to confuse the student, but in reality the are there just to clarify how the code should work.
Problem: I need to transform this list: [[1,2],[3,4],[5,6]] to [1,3,5], by taking only first items from each sub-list in first list and creating new list with all of them. Language is SWI-Prolog.
My solution: To do this, I wrote this code:
getFirstItems([], Result).
getFirstItems([H|T], Result) :-
[H2|T2] = H,
append(Result,H2,Result2),
getFirstItems(T, Result2).
Issue: But this fails to infinite recursion when tail always equals to [[5,6]]
Question: how to solve this issue and solve this problem correctly?
You are complicating things too much. You need to reason with a declarative mindset, and thus implement what the relationships between the list of lists and the list of first elements are.
Here is a solution:
first_items([], []).
first_items([[H|_]|T], [H|T2]) :-
first_items(T, T2).
Indeed, the only two things we need to state to describe that relationship are:
If the list of lists is empty, then so is the list of first elements.
a first element H is in the list of first elements, followed by the first elements (T2) of the rest of the list of lists (T).
Example queries:
?- first_items([[1,2],[3,4],[5,6]], Z).
Z = [1, 3, 5].
?- first_items(L, [1,3,4]).
L = [[1|_22058], [3|_22070], [4|_22082]].
?- first_items(L, Z).
L = Z, Z = [] ;
L = [[_22048|_22050]],
Z = [_22048] ;
L = [[_22048|_22050], [_22066|_22068]],
Z = [_22048, _22066]
…
So I'm making a predicate called removeN(List1, N, List2). It should basically function like this:
removeN([o, o, o, o], 3, List2).
List2 = [o].
The first argument is a list with a number of the same members ([o, o, o] or [x, x, x]). The second argument is the number of members you wanna remove, and the third argument is the list with the removed members.
How should I go about this, I was thinking about using length of some sort.
Thanks in advance.
Another approach would be to use append/3 and length/2:
remove_n(List, N, ShorterList) :-
length(Prefix, N),
append(Prefix, ShorterList, List).
Think about what the predicate should describe. It's a relation between a list, a number and a list that is either equal to the first or is missing the specified number of the first elements. Let's pick a descriptive name for it, say list_n_removed/3. Since you want a number of identical elements to be removed, let's keep the head of the list for comparison reasons, so list_n_removed/3 is just the calling predicate and another predicate with and additional argument, let's call it list_n_removed_head/4, describes the actual relation:
list_n_removed([X|Xs],N,R) :-
list_n_removed_head([X|Xs],N,R,X).
The predicate list_n_removed_head/4 has to deal with two distinct cases: either N=0, then the first and the third argument are the same list or N>0, then the head of the first list has to be equal to the reference element (4th argument) and the relation has to hold for the tail as well:
list_n_removed_head(L,0,L,_X).
list_n_removed_head([X|Xs],N,R,X) :-
N>0,
N0 is N-1,
list_n_removed_head(Xs,N0,R,X).
Now let's see how it works. Your example query yields the desired result:
?- list_n_removed([o,o,o,o],3,R).
R = [o] ;
false.
If the first three elements are not equal the predicate fails:
?- list_n_removed([o,b,o,o],3,R).
false.
If the length of the list equals N the result is the empty list:
?- list_n_removed([o,o,o],3,R).
R = [].
If the length of the list is smaller than N the predicate fails:
?- list_n_removed([o,o],3,R).
false.
If N=0 the two lists are identical:
?- list_n_removed([o,o,o,o],0,R).
R = [o, o, o, o] ;
false.
If N<0 the predicate fails:
?- list_n_removed([o,o,o,o],-1,R).
false.
The predicate can be used in the other direction as well:
?- list_n_removed(L,0,[o]).
L = [o] ;
false.
?- list_n_removed(L,3,[o]).
L = [_G275, _G275, _G275, o] ;
false.
However, if the second argument is variable:
?- list_n_removed([o,o,o,o],N,[o]).
ERROR: >/2: Arguments are not sufficiently instantiated
This can be avoided by using CLP(FD). Consider the following changes:
:- use_module(library(clpfd)). % <- new
list_n_removed([X|Xs],N,R) :-
list_n_removed_head([X|Xs],N,R,X).
list_n_removed_head(L,0,L,_X).
list_n_removed_head([X|Xs],N,R,X) :-
N #> 0, % <- change
N0 #= N-1, % <- change
list_n_removed_head(Xs,N0,R,X).
Now the above query delivers the expected result:
?- list_n_removed([o,o,o,o],N,[o]).
N = 3 ;
false.
As does the most general query:
?- list_n_removed(L,N,R).
L = R, R = [_G653|_G654],
N = 0 ;
L = [_G653|R],
N = 1 ;
L = [_G26, _G26|R],
N = 2 ;
L = [_G26, _G26, _G26|R],
N = 3 ;
.
.
.
The other queries above yield the same answers with the CLP(FD) version.
Alternative solution using foldl/4:
remove_step(N, _Item, Idx:Tail, IdxPlusOne:Tail) :-
Idx < N, succ(Idx, IdxPlusOne).
remove_step(N, Item, Idx:Tail, IdxPlusOne:NewTail) :-
Idx >= N, succ(Idx, IdxPlusOne),
Tail = [Item|NewTail].
remove_n(List1, N, List2) :-
foldl(remove_step(N), List1, 0:List2, _:[]).
The idea here is to go through the list while tracking index of current element. While element index is below specified number N we essentially do nothing. After index becomes equal to N, we start building output list by appending all remaining elements from source list.
Not effective, but you still might be interested in the solution, as it demonstrates usage of a very powerful foldl predicate, which can be used to solve wide range of list processing problems.
Counting down should work fine
removeN([],K,[]) :- K>=0.
removeN(X,0,X).
removeN([_|R],K,Y) :- K2 is K-1, removeN(R,K2,Y).
This works for me.
I think this is the easiest way to do this.
trim(L,N,L2). L is the list and N is number of elements.
trim(_,0,[]).
trim([H|T],N,[H|T1]):-N1 is N-1,trim(T,N1,T1).
I'm trying to create a predicate in Prolog that takes a list and returns only one copy of the adjacent duplicates of the list.
for example:
?- adj_dups([a,b,a,a,a,c,c],R).
R=[a,c]
I think I need two base cases:
adj_dups([],[]). % if list is empty, return empty list
adj_dups([X],[]). % if list contains only one element, return empty list (no duplicates).
then for the recursive part, I need to compare the head with the head of the tail, and then go recursively on the tail of the list.
This is what I came up with so far, but it doesn't work!
adj_dups([X,X|T],[X|R]):- adj_dups([X|T],R). % if the list starts with duplicates
adj_dups([X,Y|T],R):- X \= Y, adj_dups([X|T],R). % if the list doesn't start wih duplicates
How can I fix it so I can get the right result?
Edit:
I'll list some examples to help you all understand my problem.
How the code supposed to behave:
?- adj_dups([a,c,c,c,b],R).
R = [c]
?- adj_dups([a,b,b,a,a],R).
R = [b,a]
?- adj_dups([a,b,b,a],R).
R = [b]
How my code is behaving:
?- adj_dups([a,c,c,c,b],R).
R = []
?- adj_dups([a,b,b,a,a],R).
R = [a,a]
?- adj_dups([a,b,b,a],R).
R = [a]
Thank you.
I find ambiguous this specification
only one copy of the adjacent duplicates of the list
as it doesn't clarify what happens when we have multiple occurrences of the same duplicate symbol.
adj_dups([],[]).
adj_dups([X,X|T],[X|R]) :-
skip(X,T,S),
adj_dups(S,R),
\+ memberchk(X,R),
!.
adj_dups([_|T],R) :- adj_dups(T,R).
skip(X,[X|T],S) :- !, skip(X,T,S).
skip(_,T,T).
This yields
?- adj_dups([a,a,c,c,a,a],R).
R = [c, a].
Comment the + memberchk line to get instead
?- adj_dups([a,a,c,c,a,a],R).
R = [a, c, a].
Let's look at what happens when you try a simpler case:
adj_dups([a,b,b,a],R).
The first three predicates don't match, so we get:
adj_dups([X,Y|T],R):- X \= Y, adj_dups([X|T],R).
This is the problematic case: X is bound to a, Y is bound to b.
It will then call adj_dups([a,b,a],R), binding T to [b,a], which only has a single b. Effectively, you have now removed the duplicate b from the list before it could be processed.
Let's create a few auxiliary predicates first - especially a predicate that filters an element from a list. Then, in the recursive part, there are two cases:
If the first element occurs in the tail of the list being processed, it is duplicated; we need to return that first element followed by the processed tail. Processing the tail consists of removing that first element from it, then check the tail for duplicates.
The second case is much simpler: if the first element does not occur in the tail, we simply apply adj_dups to the tail and return that. The first element was never duplicated, so we forget about it.
% Filter the element X from a list.
filter(X,[],[]).
filter(X,[X|T],R) :- filter(X,T,R).
filter(X,[Y|T],[Y|R]) :- X \= Y, filter(X,T,R).
% Return "true" if H is NOT a member of the list.
not_member(H,[]).
not_member(H,[H|T]):-fail.
not_member(H,[Y|T]):-H \= Y, not_member(H,T).
% Base cases for finding duplicated values.
adj_dups([],[]). % if list is empty, return empty list
adj_dups([X],[]). % if list contains only one element, return empty list (no duplicates).
% if H1 is in T1 then return the H1 followed by the adj_dups of (T1 minus H1).
% if H1 is not in T1 then return the adj_dups of T1.
adj_dups([H1|T1],[H1|T3]):-member(H1,T1), filter(H1,T1,T2), adj_dups(T2,T3).
adj_dups([H1|T1],T3):-not_member(H1, T1), adj_dups(T1,T3).
This gives R=[a,b] for the input [a,b,b,a], and R=[a,c] for your example input [a,b,a,a,a,c,c].
Again a Prolog beginner :-}
I build up a list element by element using
(1)
member(NewElement,ListToBeFilled).
in a repeating call,
(2)
ListToBeFilled = [NewElement|TmpListToBeFilled].
in a recursive call like
something(...,TmpListToBeFilled).
A concrete example of (2)
catch_all_nth1(List, AllNth, Counter, Result) :-
[H|T] = List,
NewCounter is Counter + 1,
(
0 is Counter mod AllNth
->
Result = [H|Result1]
;
Result = Result1
),
catch_all_nth1(T,AllNth,NewCounter,Result1),
!.
catch_all_nth1([], _, _, _).
As result I get a list which looks like
[E1, E2, E3, ..., Elast | _G12321].
Of course, the Tail is a Variable. [btw: are there better method to fill up the
list, directly avoiding the "unassigned tail"?]
I was now looking for a simple method to eliminate the "unassigned tail".
I found:
Delete an unassigned member in list
there it is proposed to use:
exclude(var, ListWithVar, ListWithoutVar),!,
[Found this too, but did not help as I do not want a dummy element at the end
Prolog list has uninstantiated tail, need to get rid of it ]
What I noticed is that using length\2 eliminate the "unassigned tail", too, and in addtion
the same List remains.
My Question is: How does it work? I would like to use the mechanism to eliminate the unassigned tail without using a new variable... [in SWI Prolog 'till now I did not get the debugger
entering length() ?!]
The example:
Z=['a','b','c' | Y],
X = Z,
write(' X '),write(X),nl,
length(X,Tmp),
write(' X '),write(X),nl.
13 ?- test(X).
X [a,b,c|_G3453]
X [a,b,c]
X = [a, b, c] .
I thought X, once initialized can not be changed anymore and you need
a new variable like in exclude(var, ListWithVar, ListWithoutVar).
Would be happy if someone explain the trick to me...
Thanks :-)
You're right about the strange behaviour: it's due to the ability of length/2 when called with unbound arguments
The predicate is non-deterministic, producing lists of increasing length if List is a partial list and Int is unbound.
example:
?- length([a,b,c|X],N).
X = [],
N = 3 ;
X = [_G16],
N = 4 ;
X = [_G16, _G19],
N = 5 ;
...
For your 'applicative' code, this tiny correction should be sufficient. Change the base recursion clause to
catch_all_nth1([], _, _, []).
here are the results before
4 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d|_G75].
and after the correction:
5 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d].
But I would suggest instead to use some of better know methods that Prolog provide us: like findall/3:
?- findall(E, (nth1(I,[a,b,c,d],E), I mod 2 =:= 0), L).
L = [b, d].
I think this should do it:
% case 1: end of list reached, replace final var with empty list
close_open_list(Uninstantiated_Var) :-
var(Uninstantiated_Var), !,
Uninstantiated_Var = '[]'.
% case 2: not the end, recurse
close_open_list([_|Tail]) :-
close_open_list(Tail).
?- X=[1,2,3|_], close_open_list(X).
X = [1, 2, 3].
Note that only variable X is used.. it simply recurses through the list until it hits the var at the end, replaces it with an empty list, which closes it. X is then available as a regular 'closed' list.
Edit: once a list element has been assigned to something specific, it cannot be changed. But the list itself can be appended to, when constructed as an open list ie. with |_ at the end. Open lists are a great way to build up list elements without needing new variables. eg.
X=[1,2,3|_], memberchk(4, X), memberchk(5,X).
X = [1, 2, 3, 4, 5|_G378304]
In the example above, memberchk tries tries to make '4', then '5' members of the list, which it succeeds in doing by inserting them into the free variable at the end in each case.
Then when you're done, just close it.