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:
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) .
I want to create a predicate filter/3 or filter(Condition,List,Solution) that checks every element of the list and if returns true in the condition put it in the Solution list. How can I do this?
This is my code:
%% less_ten/1
%% less_ten(X)
less_ten(X) :- X < 10.
%% less_twenty/1
%% less_twenty(X)
less_twenty(X) :- X < 20.
%% filter/3
%% filter(C,List,Solution)
filter(_,[],Solution).
filter(C,[Head|Tail],Solution) :-
(
Predicate=..[C,Head],
call(Predicate),
!,
append(Solution,Head,NewSolution),
filter(C,Tail,NewSolution)
);
(
filter(C,Tail,Solution)
).
Seems like all you need is
filter( [] , _ , [] ) .
filter( [X|Xs] , P , [X|Ys] ) :- call(P,X), !, filter(Xs,P,Ys) .
filter( [_|Xs] , P , Ys ) :- filter(Xs,P,Ys) .
The reason for putting the source list before the test predicate is that first argument indexing can improve execution speed.
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).
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)
.
I'm trying to make intersection of 2 lists (i.e. list C contains those and only those elements, that are in A and B), yet as I understand, I get disjunction of 2 lists + any amount of any elements in C.
Intended to work like:
if X is in C, then it must be both in A and in B. (I believe X should iterate ALL members of C !?)
predicate: d(A,B,C) :- (member(X,D)->member(X,A),member(X,B)).
Can you tell: Are my sentence and predicate not equal or did I make another error?
example:
?- [user].
|: d(A,B,C) :- (member(X,D)->(member(X,A),member(X,B))).
|: % user://1 compiled 0.01 sec, 612 bytes
true.
?- d([a,b],[b,c],C)
| .
C = [b|_G21] .
?- d([a,b],[b,c],[b]).
true .
A O(NlogN) solution with duplicates removed:
% untested
intersection(A, B, O) :-
sort(A, AS),
sort(B, BS),
intersection1(AS, BS, O).
intersection1(A, B, O) :-
( A = [AH|AT],
B = [BH|BT]
-> ( AH == BH
-> O = [AH|OT],
intersection1(AT, BT, OT)
; ( AH #< BH
-> intersection1(AT, B, O)
; intersection1(A, BT, O) ) )
; O = [] ).
I like the solution proposed by #salva, though I'd do a more straightforward sort-and-merge, chucking anything that doesn't match instead:
intersect( As , Bs , Cs ) :-
sort( As , SortedAs ) ,
sort( Bs , SortedBs ) ,
merge( SortedAs , SortedBs , Cs )
.
merge( [] , [] , [] ).
merge( [] , [_|_] , [] ).
merge( [_|_] , [] , [] ).
merge( [C|As] , [C|Bs] , [C|Cs] ) :- merge( As , Bs , Cs ) .
merge( [A|As] , [B|Bs] , Cs ) :- A #< B , merge( As , [B|Bs] , Cs ) .
merge( [A|As] , [B|Bs] , Cs ) :- A #> B , merge( [A|As] , Bs , Cs ) .
your predicate d/3 should be reformulated in constructive terms, since Prolog it's 'a tuple at once' relational language:
d(X,Y,Z) :- findall(E, (member(E,X), memberchk(E,Y)), Z).
that yields
?- d([a,b],[b,c],C).
C = [b].
memberchk/2 it's the deterministic version of member/2, used here to enumerate all X' elements. You could understand better the difference if you replace memberchk with member and try to call d/3 with lists containing duplicates.
findall/3 it's the simpler 'all solutions' list constructor.