Prolog Predicate Help: Delete Number N times from List - list

Question: deleteNum(+Element, +List, -NewList, +NumToDelete) takes a list, an element, and the number of elements to delete from the List. The NewList should be the original List minus NumToDelete Elements. It does not matter which instances of the element get deleted, and no alternate answers should be given. For example,
Example:
?- deleteNum(3, [2,3,5,4,3,3], NewList, 2).
NewList = [2,5,4,3]
This is the code I tried, but it kept returning false when I attempted the example above. I'm not sure why.
deleteNum(_, [],[], 0).
deleteNum(X, [X|T], T, 0).
deleteNum(X, [H|T], [H|T1], Num):-
Num1 is Num - 1,
deleteNum(X, T, T1, Num1).
Thank you very much in advance.

You seem to be mixing up two cases with this predicate:
deleteNum(X, [H|T], [H|T1], Num):-
Num1 is Num - 1,
deleteNum(X, T, T1, Num1).
It's not removing X yet it's still reducing Num.
Here's a couple of ways to do what you want:
deleteNum(_, L, L, 0).
deleteNum(X, [H|T], [H|T1], Num) :-
X \= H,
deleteNum(X, T, T1, Num).
deleteNum(X, [X|T], T1, Num):-
Num1 is Num - 1,
deleteNum(X, T, T1, Num1).
Or:
deleteNum(_, L, L, 0).
deleteNum(X, [X|T], T1, Num):-
!,
Num1 is Num - 1,
deleteNum(X, T, T1, Num1).
deleteNum(X, [H|T], [H|T1], Num) :-
deleteNum(X, T, T1, Num).
It depends if you like ! or not.
Both succeed on ?- deleteNum(3, [2,3,5,4,3,3], NewList, 2), write(NewList), nl. and unify NewList to [2, 5, 4, 3].
Please keep in mind that Prolog doesn't return anything. It just succeeds or fails. Along the way it just tries to unify variables in order to succeed.

Not an answer but a debugging aid that would not fit a comment.
We can define a property that your predicate must satisfy:
property(Element, List, NewList, Times) :-
% first we call the predicate being tested ...
deleteNum(Element, List, NewList, Times),
% ... and then check the results
findall(Element, between(1,Times,_), Elements),
append(NewList, Elements, AllElements),
msort(List, Sorted),
msort(AllElements, Sorted).
I.e. we can recover all elements from the original list from Element, NewList, and Times. This property allows us to use property-based testing to test your predicate. Using the property-based testing support provide by Logtalk's lgtunit tool QuickCheck implementation (which you can run in most Prolog systems) we get:
?- {lgtunit(loader)}.
...
?- lgtunit::quick_check(property(+between(integer,1,10), +list(integer,1,10), -list(integer,1,10), +between(integer,1,10))).
* quick check test failure (at test 1 after 0 shrinks):
* property(1,[],A,1)
* starting seed: seed(3172,9814,20125)
false.
The failure prints a counter-example where your predicate fails: property(1,[],A,1), i.e. deleteNum(1,[],A,1). You can start by fixing this simple case. After the fix, you can run the lgtunit::quick_check/1 query again to help locate more bugs if any remaining.

Related

Comparing list elements to a predicate

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).

Append lists prolog

Given the list as input (in the format mentioned below) , I need to get the output that is a simple list of lists, If the given input list is empty then the predicate should return an empty list,
Given the input
[[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]]
I need to get the output
[[a,b],[c],[d,e],[g,h],[j,k],[h,k,l,l]]
I am having trouble performing recursion,
The code I tried is below,
function([],X):-append([],X,X).
function([Head|Tail],X):-
first(Tail,A),
append(Head,A,X),
removehead(Tail,C),
function(C,X).
where the predicates first returns first element of the list, removehead removes the first element of the list.
You make a fair attempt in the code you have shared. Here are the things that you need to improve:
The predicate name fucntion describes the fact that this predicate has one solution whenever the first argument is a list. This is typically done in the documentation, e.g. %! function(+Nested:list, -Denested:list) is det.
append([], X, X) is true by definition if X is a list, so it is superfluous here.
What are first/2, removehead/2? If you want to instantiate to the first element of a list, you can also write the clause head argument as [Head,A|C]. Then you also do not need to remove the head from Tail explicitly.
Once I make alterations based on the above I come up with the following code:
%! denest(+Nested:list, -Denested:list) is det.
denest([], []).
denest([H|T1], L):-
denest(T1, T2),
append(H, T2, L).
Example run:
?- denest([[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]], L).
L = [[a, b], [c], [d, e], [g, h], [j, k], [h, k, l|...]].
Hope this helps!

How to add and compare members in a list

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))).

PROLOG Sum of a list created from facts

I want to create a list from the facts. And the list should contains only one of the arity in the facts.
For example :
%facts
abc(a, b, c).
abc(d, e, f).
abc(g, h, i).
Sample :
?-lists(A).
A = [a, d, g];
No.
EDIT :
Using the suggestion by Vaughn Cato in the comment, the code become this :
%facts
abc(a, b, c).
abc(d, e, f).
abc(g, h, i).
lists(A) :-
findall(findall(X, abc(X, _, _), A).
The list is created, but how to sum up the list A ?
If sum of list for input from query,
sumlist([], 0).
sumlist([X|Y], Sum) :-
sumlist(Y, Sum1),
Sum is X + Sum1.
But if want to sum the existing list, how to define the predicate?
To sum a list of numbers such as that produced by your definition of lists/1, most Prolog systems (e.g., GNU, SWI) implement sum_list/2 which takes a list of numbers as the first argument and binds their sum in the second:
?- sum_list([1,2,3],Sum).
Sum = 6.
You can also solve it with aggregate_all/3. It eliminates need to build list in memory if you just need a sum.
sum_facts(Template, Arg, Sum) :-
aggregate_all(sum(X), (call(Template), arg(Arg, Template, X)), Sum).
In this example I use a generic call with defined Template:
sum_facts(abc(_, _, _), 1, Sum).
If you will always use it with the first arg of abc/3 this version will be enough:
sum_facts(Template, Arg, Sum) :-
aggregate_all(sum(X), abc(X, _, _), Sum).
As suggested by Vaughn Cato, it's help me a lot by using findall(X,abc(X, _ , _ ),A). to create the list I wanted to.

Custom reverse of a list in Prolog

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.