I have a problem with my prolog code. I need to reverse all atomic elements of list.
Example: [1,2,[3,4]] -> [[4,3],2,1]
My solution:
myReverse([], []).
myReverse([H|T], X) :- myReverse(T, RT), myAppend(RT, H, X).
But it only gives me: [[3,4],2,1]
I think, I need to use is_list function and recursive call list if it's not atomic... but I am stuck... do you guys know how to write it?
Nearly. Consider this solution:
myReverse([], []) :- !.
myReverse([H|T], X) :-
!,
myReverse(H, NewH),
myReverse(T, NewT),
append(NewT, [NewH], X).
myReverse(X, X).
The first clause is the base case, which includes a cut (!) to exclude choices left because of the last clause.
The second clause reverses the head H, which may be an atom or a list. If H is an atom, the recursive subgoal after the cut evaluates with the last clause, and atoms are passed through unchanged. If H is a list, it is evaluated with the second clause and all elements are reversed. The next subgoal does the same with the remainder of the list (the tail, T), then are finally concatenated using the built-in append/3. Note that the new head element NewH is singular, so needs to be added to a singleton list structure as [NewH] as per the definition of append/3 which operates on lists.
The last clause passes all other things (i.e., atoms, numbers, etc. - anything that isn't a list or a variable) through unchanged.
revall(L, Y) :-
revall(L, [], Y).
revall([], Y, Y).
revall([H|T], T2, Y) :-
is_list(H),!,
revall(H, Hr),
revall(T, [Hr|T2], Y).
revall([H|T], T2, Y) :-
revall(T, [H|T2], Y).
here without append
Related
Let's assume we have alphabet {x,y} and I want to create a function, which returns true or false, whether the input list contains 2x symbol x after each other.
For example two([x,x,y]). returns true, while two([x,y,x]). returns false.
This is my function that I have so far:
two([Xs]) :- two(Xs, 0).
two([y|Xs], S) :- two(Xs, S).
two([x|Xs], S) :- oneX(Xs, S).
two([], S) :- S=1.
oneX([x|Xs], S) :- S1 is 1, two(Xs, M1).
oneX([y|Xs], S) :- two(Xs, S).
I use parameter S to determine, whether there were 2x x already (if so, parameter is 1, 0 else). This function however doesn't work as intended and always return false. Can you see what am I doing wrong?
You can use unification here and thus check if you can unify the first two items of the list with X, if not, you recurse on the list:
two([x, x|_]).
two([_|T]) :-
two(T).
The first clause thus checks if the first two items of the list are two consecutive xs. The second clause recurses on the tail of the list to look for another match by moving one step to the right of the list.
I want to find rhyming couplets of a poem so I need to compare last syllables of two verses of the poem.
cmp([A|As], [B|Bs]) :- cmp(As, A, Bs, B).
cmp(A, [B], B, [A]).
cmp([_, A|As], X, [_, B|Bs], Y) :- cmp([A|As], X, [B|Bs], Y).
I need, for example, to check if "[They, put, me, in, the, oven, to, bake]" and "[Me, a, deprived, and, miserable, cake]" rhymes, so I suppose I should check if last elements of these two lists are the same.
With this code i tried to compare first and last elements of my lists but it doesn't work neither.
Some Prolog systems provide a lists library with a last/2 predicate that you can call. The usual definition is:
last([Head| Tail], Last) :-
last(Tail, Head, Last).
last([], Last, Last).
last([Head| Tail], _, Last) :-
last(Tail, Head, Last).
Note that this definition avoid a spurious choice-point, thanks to first-argument indexing, when calling the predicate with a bound list.
Using the last/2 predicate you can write:
compare_verses(Versus1, Versus2) :-
last(Versus1, Word1),
last(Versus2, Word2),
same_last_syllable(Word1, Word2).
You will now need to define the same_last_syllable /2 predicate. That will require breaking a word into a list of syllables. That doesn't seem to be trivial (see e.g. https://www.logicofenglish.com/blog/65-syllables/285-how-to-divide-a-word-into-syllables) and I'm not aware of a open source Prolog library performing it.
It sounds like you need, at least in part, a way to identify the last element of a list:
last_of( [X], X ).
last_of( [_|X], Y ) :- last_of(X, Y).
I am having trouble writing code in Prolog which takes a list, removes all primes, and returns the rest of the list. I have written a prime checker predicate, prime/1, which works just fine, but when I apply my program to the list, as with almost anything I try to do in Prolog, I get back the list without the primes, as wanted, but in reverse order.
primemover(L, Lcomp):-
primeremover(L, [], Lcomp).
primeremover([], A, A).
primeremover([H | T], A, X):-
\+ prime(H),
primeremover(T, [H | A], X).
primeremover([H | T], A, X):-
prime(H),
primeremover(T, A, X).
I can see why the list comes back reversed by looking at my code, but I just can't find a way around it. If I try reversing the head and tail of the recursive case which moves the non-prime into the middle list, it works and comes out in the correct order, but with every value in its own nested list, which is even worse than coming out backwards.
Is there a simple way to correct this issue?
I think this fixes your problem:
primeremover([], []).
primeremover([H | T], [H | Y]):-
\+ prime(H),
primeremover(T, Y).
primeremover([H | T], Y):-
prime(H),
primeremover(T, Y).
I'm not sure if I am missing something, but I believe that you are approaching this as a functional language rather than a logical language. Also, the third argument doesn't really seem to add something to the solution; it can be removed without loss of functionality.
I don't have your prime predicate but I used this to test:
main :- primeremover([1,2,3,4,5], A), write(A).
prime(X) :- X = 2; X = 3; X = 5.
I used GNU Prolog (1.4.0).
You don't need to call an auxiliar function to do this, you can do it directly by using only the input variable and the return
Code:
primeremover([], []).
primeremover([H | T], Y):-
prime(H),
!,
primeremover(T, Y).
primeremover([H | T], [H | Y]):-
primeremover(T, Y).
You're using in your primeremover/3 predicate the second argument as an accumulator, i.e. an auxiliary argument that works as a stack, collecting intermediate results. This (useful) technique is often used in the definition of recursive predicates to get the benefits of tail recursion. A canonical example of this technique is the definition of a predicate for reversing a list. The naive definition is not tail recursive and thus requires space proportional to the length of the list:
reverse([], []).
reverse([Head| Tail], Reversed) :-
reverse(Tail, Reversed0),
append(Reversed0, [Head], Reversed).
Note that the recursive call in the second clause to the reverse/2 predicate is not the last call. Thus, the append/3 predicate call that follows must be suspended by saving it in a stack until the recursive reverse/2 predicate terminates. This stack grows one element per each recursive call. But this stack will not be required if the recursive call is the last call. The tail recursive definition can be coded using an accumulator:
reverse(List, Reversed) :-
reverse(List, [], Reversed).
reverse([], Reversed, Reversed).
reverse([Head| Tail], List, Reversed) :-
reverse(Tail, [Head| List], Reversed).
But, in your specific case, and as both Erwin and Guillermo explained, there's no need to use an accumulator as you can construct the output list as you traverse the input list. The code they suggested can be, however, arguably improved by avoiding testing if the current head of the input list is a prime twice (in the case of Erwin solution) and also by avoiding a cut (in case of the Guillermo solution) by using Prolog's standard if-then-else control construct:
prime_remover([], []).
prime_remover([Head| Tail], NonPrimes):-
( prime(Head) ->
prime_remover(Tail, NonPrimes)
; NonPrimes = [Head| NonPrimesTail),
prime_remover(Tail, NonPrimesTail)
).
Note that this version is (also) tail recursive.
Here is a minimal edit of your code to correct the issue.
%%// primeremover( +L, -Lcomp)
primeremover(L, Lcomp):- %// was:
primeremover(L, [], Lcomp).
primeremover([], A, A).
primeremover([H | T], A, [H | X]):- %// primeremover([H | T], A, X):-
\+ prime(H),
primeremover(T, A, X). %// primeremover(T, [H | A], X).
primeremover([H | T], A, X):-
prime(H),
primeremover(T, A, X).
Instead of prepending - adding at the front - elements to an accumulator, and returning its final value from the deepest invocation, we append - add at the end - elements to the return list, and set its final end pointer as [] at the deepest invocation. Both are essentially iterative processes, and both are compiled by Prolog as such, i.e. with constant control stack space use.
Both variants are tail recursive, but the new one is tail recursive modulo cons.
Because the variable A no longer serves as an accumulator, and is used instead as a final "pointer" (list's last cons cell), it is customary to call it Z instead.
The new code demonstrates the "difference list" technique: the logical variables A and X form a pair, describing a list's prefix from X to A as a "difference" between a list X and its tail A.
We thus get hold of the end value explicitly, in the interface call:
primeremover(L, Lcomp):-
primeremover(L, E, Lcomp), E = [].
We could use any value for E, as we need, not just the hard-coded [], by directly calling the primeremover/3 predicate.
This is actually more natural to code in Prolog, than the usual imperative "accumulator" technique (by cons, prepending), unless we actually need to build our result in reversed order. Although, appending elements to the end of open-ended list can just as rightfully be seen as accumulating.
I am trying to write a predicate that given the following list in Prolog:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
will produce the following list:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
As you can see I would like to preserve the order of the elements at the lowest level, to produce elements in the order 1, a, b and NOT b, a, 1.
I would also like to preserve the depth of the lists, that is, lists that are originally nested are returned as such, but in reverse order.
I have managed to achieve the desired order with the following code, but the depth is lost, i.e. lists are no longer nested correctly:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
I would appreciate help in correcting the code to preserve the correct nesting of lists. Thanks!
Two suggestions. First, here's one (rev_lists/2) which uses a bunch of SWI-PROLOG built-ins:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
This one works by testing if all elements of a list L are themselves lists (M); if so, it will recursively apply itself (via maplist) over all individual sub-lists, else it will return the same list. This has the required effect.
Secondly, here's rev_lists/2 again, but written such that it doesn't rely on built-ins except member/2 (which is common):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
It's basically the same strategy, but uses an accumulator to build up reverse lists at each level, iff they are comprised exclusively of lists; otherwise, the same list is returned.
question is:
when we key in mem([1,2,3,4,5]).
we will get the output as bellow:
odd=3
even=2
my coding is like that but cannot run. can help me check where is my mistake??
mem(X,[X|L]).
mem(X,[element|L]):-
mem([X,L]).
count([],L,L).
count([X|H],L1,L2):-
write(even),
X%2=0,nl,
write(odd),
X%2>=1,nl,
count([H],[X|L1],L2).
thanks for your helping.
The procedures you have written do two different things and don't actually belong together. mem/2 is equivalent to the usually builtin member/2 except that your definition contains an error: in the second clause element is an atom instead of a variable so it will not match other elements of the list. The usual definition is
member(X, [X|_]).
member(X, [_|L]) :- member(X, L).
Note that this definition will not only test if a term is an element of a list but can even be use to generate a list.
What exactly are you trying to do in count/3: split the list into two lists, one containing odd and the other containing even; or count the number of odd and even elements? The splitting could be done with something like:
count([], [], []).
count([X|L], O, E) :- X rem 2 =/= 0, count(L, [X|O], E).
count([X|L], O, E) :- X rem 2 =:= 0, count(L, O, [X|E]).
Note that =/= /2 and =:= / 2 force evaluation of arguments as arithmetic expressions while = /2 attempts to unify its arguments.
Counting the number of odds and evens can be done in a similar fashion, and is left as an exercise for the reader. :-)