I am new to prolog. I am trying to reverse the order of list and append them.
For example :
revappend([1,2], [3,4], X) Should give me result like :
X = [3,4,1,2]
The code I wrote :
revappend([],List,List).
revappend(InputListB,[Head|InputListA], [Head|OutputList]):-
revappend( InputListA, InputListB, OutputList).
Giving me result like :
X = [15, 11, 16, 12, 13, 14]
Can someone tell me how to do this??
you want to reverse the order of list and append them or more precisely you want to append second list with the first list and here is prolog rule to do the same.
append(List,[],List).
append(List,[Head|Tail],[Head|Res]):-append(List,Tail,Res).
The 1st rule says that when the 2nd list is empty you gonna append the first list to the result.
The second rule says that you gonna add head of the second list to the result and recursively append the tail of the second list with the first list.
The problem statement is unclear to me. If what you want is to have
revappend( [1,2] , [3,4] , L ) .
produce, as your example shows:
L = [3,4,1,2]
the solution is easy:
revappend( Xs , Ys , Zs ) :- append(Ys,Xs,Zs) .
If you don't want to, or can't use, the built-in append/3, you might do something like:
revappend( [] , [] , [] ) .
revappend( Xs , [Y|Ys] , [Y|Zs] ) :- revappend( Xs , Ys , Zs ) .
revappend( [X|Xs] , [] , [X|Zs] ) :- revappend( Xs , [] , Zs ) .
However, when I hear something like your problem statement, though:
I am trying to reverse the order of list and append them.
I would expect that your
revappend( [1,2] , [3,4] , L ) .
would produce either L = [2,1,4,3] or L = [4,3,2,1].
For the former ([2,1,4,3]) case, you might write something like this:
revappend( Xs, Yz , Zs ) :- revappend(Xs,Yz,[],Zs) .
revappend( [] , [] , Zs , Zs ) .
revappend( [X|Xs] , Ys , Rs , Zs ) :- revappend(Xs,Ys,[X|Rs],Zs).
revappend( [] , [Y|Ys] , Rs , Zs ) :- revappend([],Ys,[Y|Rs],Zs).
For the latter ([4,3,2,1]), you just need to change things up a bit, modifying revappend/4 along these lines:
revappend( [] , [] , Zs , Zs ) .
revappend( Xs , [Y|Ys] , Rs , Zs ) :- revappend(Xs,Ys,[Y|Rs],Zs).
revappend( [X|Xs] , [] , Rs , Zs ) :- revappend(Xs,[],[X|Rs],Zs).
Note that you can do this with built-ins as well:
revappend(Xs,Ys,Zs) :-
reverse(Xs,X1) ,
reverse(Ys,Y1) ,
append(X1,Y1,Zs)
.
Related
I'm trying to implement a simple predicate, that would simply remove items that occur more than once in a list.
For instace, for,
unique([a,b,a,b,c,c,a], R)
should be R = [a,b,c]
unique([], []).
unique([X], [X]).
unique([H|T], [H|R]) :-
not_contains(H, R),
unique(T, R).
unique([H|T], R) :-
contains(H, R),
unique(T, R).
contains(_, []).
contains(X, [X|T]).
not_contains(_, []).
not_contains(X, [H|T]) :-
X \= H,
not_contains(X, T).
I am unsure what I'm doing wrong. If the item is not contained within R, add to it and repeat, and if is, don't add it and proceed with iteration.
A fun way to do it that I just thought of:
nub(L,R):- maplist( p(R), L), length(R,_), !.
p(R,E):- memberchk(E,R).
nub(L,R) makes a unique list R out of an input list L. It assumes R is a non-instantiated variable before the call is made, and L is a fully ground list.
This uses the result list as its own uniqueness accumulator while it is being built!
Testing:
6 ?- nub([a,b,a,b,c,c,a], R).
R = [a, b, c].
The easiest way to make a list unique is just use the built-in sort/2:
unique(Xs,Ys) :- sort(Xs,Ys).
so unique( [c,a,b,a] , Rs ) yields Rs = [a,b,c].
If you want to maintain order, you need to decide on the strategy you want to use — in case of duplicates, which duplicate "wins": First or last?
The "last wins" strategy is the simplest to implement:
unique( [] , [] ) . % the empty list is itself a unique set
unique( [X|Xs] , Ys ) :- % A non-empty list is unique if . . .
contains(X,Xs), % - X is contained within the source list's tail,
!, - and (eliminating the choice point)
unique( Xs, Ys ) . - omitting X, the remainder of the list is (recursively) unique
unique( [X|Xs] , Ys ) :- % Otherwise, the non-empty list is unique if . . .
unique( Xs,[X|Ys] ) . % - adding X to the results, the remainder of the list is (recursively) unique .
Here, unique( [a,b,a,c,a], Rs ) yields Rs = [b,c,a].
If you want to use the "first wins" strategy, you'll be wanting to use a helper predicate with an accumulator that grows the result list in reverse order, which is then reversed. That gives us something like this:
unique( Xs , Ys ) :- unique(Xs,[],Zs), reverse(Zs,Ys) .
unique( [] , Ys , Ys ) . % Source list exhausted? we're done.
unique( [X|Xs] , Ts , Ys ) :- % Otherwise . . .
contains(X,Ts) , % - if X is found in the accumulator,
!, % - eliminate the choice point, and
unique(Xs,Ts,Ys) . % - recurse down, discarding X
unique( [X|Xs] , Ts , Ys ) :- % Otherwise (X is unique) . . .
unique(Xs,[X|Ts],Ys) . % - recurse down, prepending X to the accumulator
And here, unique( [a,b,a,c,a], Rs ) yields Rs = [a,b,c].
You can avoid the use of reverse/2 here, by building the 2 lists (accumulator and final set) in parallel. A trade-off, though: memory for speed:
unique( Xs , Ys ) :- unique(Xs,[],Ys) .
unique( [] , _ , [] ) .
unique( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts), !, unique( Xs, Ts , Ys ) .
unique( [X|Xs] , Ts , [X|Ys] ) :- unique( Xs, [X|Ts] , Ys ) .
You don't really need a contains/2 predicate: the in-built member/2 and memberchk/2 do exactly what you want. member/2 is non-deterministic and will succeed once for every time the item is found in the list; memberchk/2 is non-deterministic and will succeed at most once.
Since this is testing for uniqueness, memberchk/2 is what you'd want, giving you this:
contains(X,Ys) :- memberchk(X,Ys) .
Or you can roll you own (it's trivial):
contains( X , [X|Ys] ) :- ! .
contains( X , [_|Ys] ) :- contains(X,Ys) .
Or even simpler, just a one-liner:
contains( X , [Y|Ys] ) :- X = Y -> true ; contains(X,Ys) .
There is an initial list, split into two lists of the same length (ex. a list of 10 elements, split into 5 elements each), please, can anyone know with explanations desirable. Input: [1,2,3,4,5,6,7,8,9,10] Output: [1,2,3,4,5] [6,7,8,9,10] My beginnings:
len([],0).
len([X|L],N):-len(L,M),N is M+1.
?-len([1,2,3,4,5],X),write(X),nl.
%split([],[],[]).
%split([A],[A],[]).
%split([A|T],[A|T1],[B|T2]):-
% split(T,T1,T2).
%?-split([1,2,3,4,5,6],Lst1,Lst2),write(Lst1),write(Lst2),nl.
If the list item order doesn't matter to you, you might find the following split/3 congenial.
split([],[],[]).
split([X|Xs],[X|Ys],Zs) :-
split(Xs,Zs,Ys).
Sample queries using GNU Prolog 1.5.0:
| ?- split([a,b,c,d],Xs,Ys).
Xs = [a,c]
Ys = [b,d]
yes
| ?- split([a,b,c,d,e],Xs,Ys).
Xs = [a,c,e]
Ys = [b,d]
yes
If order doesn't matter, then just:
partition( [] , [] , [] ) .
partition( [Y] , [Y] , [] ) .
partition( [Y,Z|Xs] , [Y|Ys] , [Z|Zs] ) :- partition(Xs,Ys,Zs) .
If order is important, then the easiest way would be to simply
partition( Xs , Ys , Zs ) :-
length(Xs,N),
M is N div 2,
length(Ys,M),
append(Ys,Zs,Xs) .
[Though probably not what your instructor is looking for.]
Something like this would work:
partition( Xs , Ys, Zs ) :-
length(Xs,N0),
N is N0 div 2 ,
partition( N , Xs, Ys, Zs )
.
partition( 0 , Zs , [] , Zs ) .
partition( N , [X|Xs] , [X|Ys] , Zs ) :- N1 is N-1, partition(N1,Xs,Ys,Zs).
It runs in O(N) time — O(1.5N) actually. It traverses the source list once to determine its length, and then again to partition it.
As would this:
partition( Xs , Ys , Zs ) :- partition(Xs,Xs,Ys,Zs) .
partition( [] , Xs , [] , Xs ) .
partition( [_] , [X|Xs] , [X|Ys] , Xs ) .
partition( [_,_|Ts] , [X|Xs] , [X|Ys] , Zs ) :- partition(Ts,Xs,Ys,Zs ) .
Here you pass the source list to the helper predicate twice. From the one list, we strip two items on each iteration, and from the other, a single item. Once the list we're stripping two items from it exhausted, we're done.
This runs in O(N) time as well — O(N/2) actually, so it's somewhat more time efficient.
I'm new to learn the prolog, I want to fulfill the predicate below.
removereverse([[1,5],[5,1],[2,3],[3,2]],List). ---> Input
what I want:
List = [[1,5],[2,3]].
mycode
removes([],[]).
removes([[N1,N2]|T],[[N1,N2]|New]):-
\+member([N1,N2],New),
removes(T,New).
Something like this?
First, lets define a predicate to tell us if a list is duplicated within a list-of-lists. This counts a list as a duplicate if either it or its reverse exists in the target list-of-lists:
duplicated(X,Ls) :- member(X,Ls).
duplicated(X,Ls) :- reverse(X,R), member(R,Ls).
Then we can say:
clean( [] , [] ) .
clean( [X|Xs] , Ys ) :- duplicated(X,Xs), !, clean(Xs,Ys) .
clean( [X|Xs] , [X|Ys] ) :- clean(Xs,Ys) .
That keeps the last "duplicate" found and discard those preceding them in the source list. To keep the first such "duplicate" instead, just change where the recursion occurs:
clean( [] , [] ) .
clean( [X|Xs] , Ys ) :- clean(Xs,Ys), duplicated(X,Xs), !.
clean( [X|Xs] , [X|Ys] ) :- clean(Xs,Ys).
Another approach uses a helper predicate:
This keeps the first:
clean( Xs, Ys ) :- clean(Xs,[],Y0), reverse(Y0,Ys).
clean( [] , Ys, Ys ) .
clean( [X|Xs] , Ts, Ys ) :- duplicated(X,Ts), !, clean(Xs, Ts ,Ys).
clean( [X|Xs] , Ts, Ys ) :- clean(Xs,[X|Ts],Ys).
To keep the last, simply change duplicate(X,Ts) to duplicate(X,Xs). The former checks to see if X exists in the accumulator Ts; the latter checks to see if X exists in the tail of the source list (Xs).
How can I remove ! from this rule for it to work properly ?
extractvowels([],[]).
extractvowels([H|T],R):-consonant(H),extractvowels(S,R),!.
extractvowels([H|T],[H|R]):-extractvowels(S,R),!.
consonant(H) contains all the consonants.
And how can I join this rule(distinct) within the extractvowels one ?
member(X, [X|_]).
member(X, [_|Tail]) :- member(X, Tail).
distinct([],[]).
distinct([H|T],C) :- member(H,T), distinct(T,C),!.
distinct([H|T],[H|C]) :- distinct(T,C).
I can't use any prolog predicate.
This doesn't address directly your question, already answered by Sergey, rather suggest a 'programming style' that attempt to avoid 'boilerplate' code, and - sometimes - cuts.
Consider this simple query - it's plain Prolog (apart the extended string notation, `hello world`, SWI-Prolog specific) , and can 'solve in a line':
?- S=`hello world`, findall(C, (member(C, S), C > 0'a, C =< 0'z, \+ memberchk(C, `eiou`)), Cs), format('~s~n', [Cs]).
hllwrld
S = [104, 101, 108, 108, 111, 32, 119, 111, 114|...],
Cs = [104, 108, 108, 119, 114, 108, 100].
What's interesting to note: see how member/2 inside findall/3 acts as a lambda expression and search space generator, allowing to name the variable - we can call it the 'local environment' - and then allowing what Prolog play best - clause solving.
General and easy, isn't it ?
This should work:
extractvowels([], []).
extractvowels([H|T], R) :- consonant(H), extractvowels(T, R).
extractvowels([H|T],[H|R]) :- \+ consonant(H), extractvowels(T, R).
I fixed your singleton variables 'S' - changed to 'T' (SWI-Prolog probably complained about this, and you should fix any singleton variables warnings).
You last extractvowels cut ('!') could be just removed - a cut at the end of the last clause does nothing.
To get rid of the first cut I added a "guard" rule \+ consonant(H) to the last extractvowels clause - proceed only if H is not a consonant.
Assuming that your definition of "vowel" is "that which is not a consonant" (there are lots of characters, most of which are neither vowels, nor consonants), and if by "extract vowels", you mean
remove all the vowels, leaving only the consonants
then something like this would work:
consonants_in( [] , [] ) .
consonants_in( [X|Xs] , [X|R] ) :- consonant(X) , consonants_in(Xs,R) .
consonants_in( [X|Xs] , R ) :- \+ consonant(X) , consonants_in(Xs,R) .
You could also say something like:
consonants_in( [] , [] ) .
consonants_in( [X|Xs] , R ) :-
( consonant(X) -> R = [X|R1] ; R = R1 ) ,
consonants_in( Xs , R1 )
.
If on the other hand, if by "extract vowels" , you mean
remove all the consonants, leaving only the vowels
then you want the inverse, something like
vowels_in( [] , [] ) .
vowels_in( [X|Xs] , [X|R] ) :- \+ consonant(X) , vowels_in(Xs,R) .
vowels_in( [X|Xs] , R ) :- consonant(X) , vowels_in(Xs,R) .
or
vowels_in( [] , [] ) .
vowels_in( [X|Xs] , R ) :-
( consonant(X) -> R = R1 ; R = [X|R1] ) ,
vowels_in( Xs , R1 )
.
You could make things more declarative by making your definition of "vowel" explicit:
vowel(C) :- \+ consonant(C) .
and change your predicates accordingly:
vowels_in( [] , [] ) .
vowels_in( [X|Xs] , [X|R] ) :- vowel(X) , vowels_in(Xs,R) .
vowels_in( [X|Xs] , R ) :- \+ vowel(X) , vowels_in(Xs,R) .
or
vowels_in( [] , [] ) .
vowels_in( [X|Xs] , R ) :-
( vowel(X) -> R = [X|R1] ; R = R1 ) ,
vowels_in( Xs , R1 )
.
The advantage of this is that you could modify you definition of "vowel" later to be more correct,
vowel(a).
vowel(e).
vowel(i).
vowel(o).
vowel(u).
without affecting the rest or your code:
Having trouble understanding how Prolog works. I'm tryig to write a rule that takes three lists of integers as input (representing sets) and puts the integers that belong to both the first and second list in the third list.
Example:
?-inter([10,20,30,40],[10,50,40,60], List3 )
List3 = [10, 40]
So far I have this, that can recognize if a list contains a certain letter:
mymember(X,[X|T]).
mymember(X,[H|T]) :- mymember(X,T).
There's actually an inbuilt library to sort that all out for you, known as ordsets.
inter(X, Y, Z) :-
list_to_ord_set(X, L1),
list_to_ord_set(Y, L2),
ord_intersection(L1, L2, Z).
Using your example input you get the following
| ?- inter([10,20,30,40],[10,50,40,60],X).
X = [10,40] ? ;
no
inter(Xs, Ys, Zs) will be true when each element in Zs also is in Xs and in Ys.
But Zs are unknown, then a more constructive approach is required.
Here it is: iterate on Xs and store in Zs each element that is in Ys.
An example of iteration is mymember/2, you can see that it requires a recursive predicate.
The other idiomatic part of the above statement is store in Zs, Prolog has a peculiar way to do such things, using pattern matching.
inter([X|Xs], Ys, [X|Zs]) :-
mymember(X, Ys), inter(Xs, Ys, Zs).
You will need to complete inter/3 with other 2 clauses: base recursion, i.e. when all Xs elements have been processed, and the case where X is not a member of Ys.
Try something like this, using the builtins member/2 and setof\3:
set_intersection( As , Bs , Xs ) :-
set_of( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
One should note that this will fail if the lists As and Bs have no elements in common. An alternative would be use findall/3 rather than set_of/3. findall/3 will hand back and empty list rather than failure if the goal is not satisfied:
set_intersection( As , Bs , Xs ) :-
findall( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
However findall/3 returns a bag (duplicates are allowed) rather than a set (no duplicates allowed), so if your two source lists aren't sets, you won't get a set out.
member/2 is a builtin predicate that unifies its first argument with an element of the list — the equivalent of
member(X,[X|_).
member(X,[_|Xs) :- member(X,Xs) .
And, finally, as #chac noted in his answer, you can recursively traverse the list.
set_intersection( [] , _ , [] ) . % the intersection of the empty set with anything is the empty set.
set_intersection( [A|As] , Bs , [A|Xs] ) :- % if the list is non-empty,
member(A,Bs) , % - and A is a member of the 2nd set
! , % - we cut off alternatives at this point (deterministic)
set_intersection( As , Bs , Xs ) % - and recurse down on the tail of the list.
.
set_intersection( [_|As] , Bs , Xs ) :- % if the list is non-empty, and A is NOT a embmer of the 2nd set
set_intersection( As , Bs , Xs ) % we just recurse down on the tail of the list.
.
#chac's technique builds the result list as he goes, something like:
[a|X]
[a,b|X]
[a,b,c|X]
The final unification, the special case of the empty list unifies the unbound tail of the list with [] making the list complete, so the final [a,b,c|X] becomes
[a,b,c]
A little prolog magic. An alternative that might be easier to understand is to use a worker predicate with an accumulator:
%
% set_intersection/3: the public interface predicate
%
set_intersection( As , Bs , Xs ) :-
set_intersection( As , Bc , [] , T ) % we seed our accumulator with the empty list here
.
%
% set_intersection/4: the private worker bee predicate
%
set_intersection( [] , _ , T , Xs ) :- % since our accumulator is essentially a stack
reverse(T,Xs) % we need to reverse the accumulator to
. % put things in the expected sequence
set_intersection( [A|As] , Bs , T , Xs ) :-
member( A, Bs ) ,
! ,
T1 = [A|T] ,
set_intersection( As , Bs , T1 , Xs )
.
set_intersection( [_|As] , Bs , T , Xs ) :-
set_intersection( As , Bs , T , Xs )
.