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).
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 have a certain list which is generated from a predicate and looks like this:
[a, b, c]
I also have a following predicate p/3 that could be applied to each element of my list:
?- p(a, NewList, Number).
and it will return:
NewList = [c, d],
Number = 2.
where NewList is a newly generated list from a element, and Number is the NewList length.
Problem:
I want to apply the p/3 predicate to all elements, and get
one list which consists of all elements from all NewLists aka all NewLists appended together
and the sum of all Numbers.
I tried to do it like this:
loop_list([Element|[]], NewList, Number) :-
p(Element, NewList, Number).
loop_list([Head|Tail], [Tmp|NewList], Number) :-
loop_list(Tail, Tmp, Number).
but failed.
It is often better to separate your concerns, and solve one task at once. You can use maplist/4 [swi-doc] here to call the predicate over all the elements in the list. This will then unify the third and the fourth element with the results of p/3.
Next we can make use of append/2 [swi-doc] to append lists together, and sumlist/2 [swi-doc] to sum the elements of a list together.
We thus can implement this as:
loop_list(Ls, Xs, Sum) :-
maplist(p, Ls, Xss, Items),
append(Xss, Xs),
sumlist(Items, Sum).
I need to construct a a predicate compare_to_predicate/3. It takes in a given predicate and list of numbers and proceeds to compare every element in the list using that predicate.
The given predicates are
- is_odd
- is_even
- greater_than(X)
For example:
?- compare_to_predicate([8,13,1,500], [is_odd], X).
X = [13, 1].
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
X = [13, 500].
What I have come up with thus far is:
is_odd(X):- 1 is mod(X,2).
is_even(X):- 0 is mod(X,2).
greater_than(X,Y):- X<Y.
compare_to_predicate([],_,[]).
compare_to_predicate([H|Tail],Functor,[H|X]):- Term =.. [Functor,H], Term, compare_to_predicate(Tail,Functor,X).
I have a number of issues:
1)
?- compare_to_predicate([2,10,8,300],is_even,X).
will produce
X = [2, 10, 8, 300].
but
compare_to_predicate([2,10,8,301],is_even,X).
will produce
false.
I assume it has to do with the predicate encountering a number that will not return true on is_even and then terminating the whole compare_to_predicate with a false. In that case is the solution to somehow make it ignore odd numbers instead of evaluating them? If so, how would I do that?
2)
It seems that the given predicate I pass into compare_to_predicate has to have the type List as seen in
?- compare_to_predicate([8,13,1,500], [is_odd], X).
and
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
I am currently simply passing a normal predicate into the Term. I'm not quite sure on how I'm supposed to do that.
It seems that compare_to_predicate([H|Tail],[Functor],[H|X]):- Term =.. [Functor,H], Term, compare_to_predicate(Tail,[Functor],X)
did the trick here. Finally:
3)
?- compare_to_predicate([8,13,1,500], [greater_than, 10], X).
It seems I need to make compare_to_predicate able to take in predicates with different arity as shown here. Is the solution supposed to be something like this?
(Term =.. [Functor,A]; Term=.. [Functor,A,B]).
Any help will be appreciated.
You kind of need to decide what compare_to_predicate/3 is supposed to do with values that fail the goal. I see basically three ways this can go:
It can behave as a filter, and the third argument is unified with the values in the first argument that pass.
It can behave as a for-all, and the third argument is unified with the whole list if they all pass and fails otherwise (your current behavior)
It can behave like an for-each that just applies the predicate to each item in the list and discards the result. There is no meaningful value for the third parameter in this case.
By the way, the term surgery you're doing with =../2 is not necessary; call/N will do the right thing if you do something like call(greater(10), 20), so you can just allow the user to call your predicate like this: compare_to_predicate([1,2,3,4], greater(2), X) and use call to build the goal.
Doing the first one is pretty straightforward:
filter([], _, []).
filter([X|Xs], P, Result) :-
filter(Xs, P, Xs1),
(call(P, X) -> Result = [X|Xs1] ; Result = Xs1).
Doing the second one is also pretty straightforward:
forall([], _, []).
forall([X|Xs], P, [X|Xs]) :- call(P, X), forall(Xs, P, Xs).
Doing the third one is not terribly hard:
foreach([], _).
foreach([X|Xs], G) :- once(call(G, X) ; true), foreach(Xs, G).
I am new to prolog. I am trying to write a predicate that accepts an element and list and checks to see the occurrence of the element in the list and returns the rest of the list after the element.
Example is mypredicate(3, [1 2, 3, 4, 5, 6, 7])
returns [3, 4, 5, 6, 7].
I hope I am able to explain.
mypredicate(X, [X|_]).
mypredicate(X, [_|T]) :- mypredicate(X,T).
This is basically just checking if the element is there in the list.
How do I write a rule that returns the rest of the list after X?
You need to return all the list in the base case like:
mypredicate(X, [X|T],[X|T]).
Also the clause:
mypredicate(X, [_|T]) :- mypredicate(X,T).
is used when the head of the list is X, so you need to make sure that in this case the head is different from X like:
mypredicate(X, [H|T],L) :- dif(X,H),mypredicate(X,T).
you should add a third argument
mypredicate(X,[X|L],[X|L]).
mypredicate(X,[_|T],L) :- mypredicate(X,T,L).
If you're interested only to the first occurrence of X and L, add a cut at the first rule:
mypredicate(X,[X|L],[X|L]) :- !.
Another way, use a library(lists) predicate:
edit corrected after comment by #tim.newport
mypredicate(X,L,[X|T]) :- append(_,[X|T],L).
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))).