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.
Related
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 have created a predicate that will check whether all the items in a list satisfy a condition.
For this example, the predicate checks that all elements are in multiples of two Check_Multiples/1, which works quite well.
How would I check to see what item could be added to the beginning or the end of the list, and still satisfy the predicate?
I am trying to make the return a list.
For example:
[2,4,6]
should return [8] as (as the predicate does not allow 0)
[6,8,10]
should return [4,12]
The following code should do the trick, given that Check_Multiples checks if every element of the list is a multiple of two in an ascending order. I'm guessing that was a condition, otherwise if lists such as [4, 6, 4, 4, 8] were allowed you could just check if every element modulus 2 is equal to 0.
additionsToList([H|T], ResultList) :-
Check_Multiples([H|T]),
firstElement(H, First),
lastElement(T, Last),
append([First],[Last], Z),
flatten(Z, ResultList).
firstElement(2, []).
firstElement(First, X) :-
X is First-2.
lastElement([H|[]], X) :-
X is H+2.
lastElement([_|T], X) :-
lastElement(T, X).
I'm trying to write a predicate is_multi(M), defined as:
every element of M has the form X / N, where X is an atom, and N is an integer greater than 0;
M does not contain two elements with the same atom, for what
is_multi([]).
is_multi([a / 2, b / 2]).
are satisfied, but
is_multi([a, b/2]).
is_multi([a/0, b/2]).
is_multi([a/2, 2/4])
is_multi([a/2, b/3, a/2])
is_multi([a/3, b/-4, c/1])
are not.
Here's what I have written so far:
is_multi(M) :- M = [].
is_multi(M) :-
M = [Head|Tail],
Head = X/N,
integer(N),
N > 0,
is_multi(Tail).
But it does not compare two elements if with the same atom. For example, is_multi([a/2, a/3]) is not satisfied. I got stuck for one day with this; could somebody give me some hints?
First, you can simplify your code considerably by moving some of your unifications from the body to the head.
is_multi([]).
is_multi([X/N|Tail]) :-
integer(N), N > 0,
is_multi(Tail).
Cleaning it up reveals one thing you're not doing here which is in your spec is checking that X is an atom. Fix by adding atom(X) to the body.
OK, so this takes care of the basic form, but doesn't ensure that the atoms do not repeat. The simplest thing to do would be to split this into two checks, one that checks that each item is well-formed, and one that checks that the list is well-formed. In fact, I would be inclined to use maplist/2 with a predicate that checks a single element. But all you really have to do is something like this:
is_valid([]).
is_valid([X/_|T]) :- is_valid(T), \+ memberchk(X/_, T).
This just says that the empty list is valid, and if the tail is valid, a list is valid if X over something doesn't occur in the tail.
If that's all you wanted, stop reading there. If you want to refactor, this is how I would approach it:
well_formed(X/N) :- atom(X), integer(N), N > 0.
no_repeating_numerators([]).
no_repeating_numerators([X/_|T]) :- no_repeating_numerators(T), \+ memberchk(X/_, T).
is_multi(L) :- maplist(well_formed, L), no_repeating_numerators(L).
Just to complete Daniel's instructive answer (+1 by me), I want to showcase how your task could be solved by means of some library predicates:
is_multi(L) :-
forall(select(E, L, R),
(E = A/N, atom(A), integer(N), N > 0, \+memberchk(A/_, R))).
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
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. :-)