How do I write a procedure in Prolog that clears a list of integers of its negative elements and returns the result in a new list? Without using cuts but can use negation.
For example:
?- filter([1,0,-6,7,-1],L).
L = [1,0,7];
no
You have it almost right.
Your solution was:
filter([],[]).
filter([H|T],S) :-
H<0,
filter(T,S).
filter([H|T],S) :-
H>=0,
filter(T,[H|S]).
The base case and the case where the item is negative are right.
The problem is with the last case. Once you checked that the item is nonnegative you know that the item will be on the resulting list. Therefore you should do the recursion and return a list that contains the element you have checked (H) and the list returned by recursion. Thus, the last clause should be
filter([H|T],[H|S]) :-
H>=0,
filter(T,S).
In SWI-Prolog you can use exclude/3
?- exclude(negative, [-1, -0.5, 0, 0.5, 1], L).
L = [0, 0.5, 1].
provided that you have a definition for negative/1:
negative(Number) :-
Number < 0.
Using recursion for the last case,
I'd write :
filter([],[]).
filter([H|T],S) :-
H<0,
filter(T,S).
filter([H|T], L) :-
H>=0,
filter(T, S),
append([H],S,L).
Related
I am new to Prolog and I am trying to write a function that finds a list that follows some rules.
More specifically, given two numbers, N and K, I want my function to find a list with K powers of two that their sum is N. The list must not contain each power but the total sum of each power. For example if N=13 and K=5, I want my list to be [2,2,1] where the first 2 means two 4, the second 2 means two 2, and the third 1 means one 1 (4+4+2+2+1=13). Consider that beginning from the end of the list each position i represents the 2^i power of 2. So I wrote this code:
sum2(List, SUM, N) :-
List = [] -> N=SUM;
List = [H|T],
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
powers2(N,K,X):-
sum2(X,0,N),
sum_list(X, L),
K = L.
The problem is:
?- sum2([2,2,1],0,13).
true.
?- sum2([2,2,1],0,X).
X = 13.
?- sum2(X,0,13).
false.
?- powers2(X,5,[2,2,1]).
X = 13.
?- powers2(13,5,[2,2,1]).
true.
?- powers2(13,X,[2,2,1]).
X = 5.
?- powers2(13,5,X).
false.
In the cases, X represents the list I expected the output to be a list that follows the rules and not false. Could you help me to find how can I solve this and have a list for output in these cases?
The immediate reason for the failure of your predicate with an unbound list is due to your use of the -> construct for control flow.
Here is a simplified version of what you are trying to do, a small predicate for checking whether a list is empty or not:
empty_or_not(List, Answer) :-
( List = []
-> Answer = empty
; List = [H|T],
Answer = head_tail(H, T) ).
(Side note: The exact layout is a matter of taste, but you should always use parentheses to enclose code if you use the ; operator. I also urge you to never put ; at the end of a line but rather in a position where it really sticks out. Using ; is really an exceptional case in Prolog, and if it's formatted too similarly to ,, it can be hard to see that it's even there, and what parts of the clause it applies to.)
And this seems to work, right?
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
OK so far, but what if we call this with an unbound list?
?- empty_or_not(List, Answer).
List = [],
Answer = empty.
Suddenly only the empty list is accepted, although we know from above that non-empty lists are fine as well.
This is because -> cuts away any alternatives once it has found that its condition is satisfied. In the last example, List is a variable, so it is unifiable with []. The condition List = [] will succeed (binding List to []), and the alternative List = [H|T] will not be tried. It seems simple, but -> is really an advanced feature of Prolog. It should only be used by more experienced users who know that they really really will not need to explore alternatives.
The usual, and usually correct, way of implementing a disjunction in Prolog is to use separate clauses for the separate cases:
empty_or_not([], empty).
empty_or_not([H|T], head_tail(H, T)).
This now behaves logically:
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
?- empty_or_not(List, Answer).
List = [],
Answer = empty ;
List = [_2040|_2042],
Answer = head_tail(_2040, _2042).
And accordingly, your definition of sum2 should look more like this:
sum2([], SUM, N) :-
N = SUM.
sum2([H|T], SUM, N) :-
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
This is just a small step, however:
?- sum2(X, 0, 13).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] _2416 is 0+_2428* ...
ERROR: [8] sum2([_2462],0,13) at /home/gergo/sum.pl:5
ERROR: [7] <user>
You are trying to do arithmetic on H, which has no value. If you want to use "plain" Prolog arithmetic, you will need to enumerate appropriate values that H might have before you try to do arithmetic on it. Alternatively, you could use arithmetic constraints. See possible implementations of both at Arithmetics in Prolog, represent a number using powers of 2.
I am very new to prolog and I'm trying to sum the elements of a list.
So far, I have this:
sum([],_,_). %base case
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
testing with sum([1,2,3,4], 0, X) results in an error, but I'm not sure what's wrong with this code. Could someone point me in the right direction?
The code you gave is closer to working than you probably think, but it has a couple problems.
For one, Prolog predicates aren't functions, they don't return results like functions in other languages do. Predicates, instead, declare something about what is true. Later you can give prolog queries and it'll try to make them true.
For example, calls to length/2 are true when the left argument is a list, and the right argument is an int with the length of the list:
?- length([1, 2, 3, 4], 4).
true.
?- length([1, 2, 3, 4], X).
X = 4.
?- length(X, 2).
X = [_2300, _2306].
Looking back at your first line:
sum([],_,_). %base case
This says "sum/3 is always true, as long as the first element is an empty list". You can test this:
?- sum([], -20, hello).
true.
That's probably not what you were intending.
I'm not sure how to put the rest of this without just giving away the answer, but look at what this clause is saying:
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
"sum([H|T], Y, WhoCaresIllNeverUseThisVariable) is true if we can recur and prove that sum(T, H+Y, H+Y) is true".
Well, one point, that last argument is a little weird, because in both clauses you assign it to an anonymous variable (_ and _X). What you're saying is, "the third argument never matters and should match literally anything the uses throws at it". I don't think that's what you mean to say.
Second point, I don't know if you realize it but, you're actually computing a sum here! While trying to make sum([1, 2, 3, 4], 0, X) true Prolog will traverse the list and add each element to the middle argument, your accumulator. The summing part works! What you're failing to do is extract the sum from this predicate.
Generally in Prolog you "return" results by making them an additional argument. You could look at length/2 this way. Here's a way you might write it yourself:
my_length([], 0).
my_length([_|Rest], Length) :-
my_length(Rest, Length1),
Length is Length1 + 1.
This function "returns" the length of the array by only being true when the second argument of the predicate is the length of the array.
I am working on a problem for homework. I am trying to get all the unique permutations of 0 and 1 where the number of 0s and 1s is passed in to binaryLists/3. I have a set of rules that will get the permutations, but I get a large number of duplicates as permutation/2 treats each 0 and 1 as unique. I feel like I need to put a cut somewhere, but I don't really understand cuts and I'm not sure how to think about this. My code is as follows:
binaryLists(0, 0, R).
binaryLists(Z, O, R) :-
Z >= 0, O >= 0,
generateZero(Z, Lz),
generateOne(O, Lo),
append(Lz, Lo, Tmp),
permutation(Tmp, R).
generateZero(0, R) :-
R = [].
generateZero(Z, R) :-
Z > 0,
Y is Z - 1,
generateZero(Y, Tmp),
append(Tmp, [0], R).
generateOne(0, R) :-
R = [].
generateOne(Z, R) :-
Z > 0,
Y is Z - 1,
generateOne(Y, Tmp),
append(Tmp, [1], R).
The result of this will give many duplicates of the same list (e.g. [1, 0, 0, 0]).
A cut won't help you here. It's a common Prolog beginner mistake to make rules overly complex and procedural, then try to fix things with cuts.
Here are some hints. You don't need append/3, permutation/2, and you don't need a 0/1 list generator.
Your first rule is on the right track, but has a flaw. You have the singleton R. You're trying to say that a list with 0 zeroes, and 0 ones, should be an empty list. So just say that:
binaryList(0, 0, []).
Now you can define two more rules which give the conditions for when the resulting list should start with a 1 and when it should start with a 0. Those are the only two additional rules you need:
binaryList(Zeroes, Ones, [0|R]) :-
Zeroes > 0,
... % What goes here?
binaryList(..., Ones, R). % What goes in place of ...?
binaryList(Zeroes, Ones, [1|R]) :-
Ones > 0,
... % What goes here?
binaryList(Zeroes, ..., R). % What goes in place of ...?
Once you create the proper rules in Prolog that define what makes a valid list, then Prolog will do the work for you in terms of exploring all of the possible solutions that satisfy the rules. That's how you get all of the permutations. The permutations are unique because the rules are non-overlapping in their solutions and ensure that each solution is different.
I want to create a list consisting of N elements.
I write the following code:
DOMAINS
list = integer*
PREDICATES
create(integer, integer, list)
CLAUSES
create(_, 0, []).
create(Start, End, [Start|T]):-
Start < End + 1,!,
Counter = Start + 1,
create(Counter, End, T).
GOAL
create(1, 5, L).
But it returns me No Solution.
On the other hand if I change the direction of my Counter like this:
DOMAINS
list = integer*
PREDICATES
create(integer,list)
CLAUSES
create(0,[]).
create(N,[N|T]):-
N > 0,
NN = N - 1,
create(NN,T).
GOAL
create(5,L).
It returns me 1 Solution: L=[5,4,3,2,1]. It's working good, but not in the order.
What wrong in my first variant of code?
You need to make some adjustments to your program:
The stop clause is never unified, because you don't decrement the
End term.
Counter need to be evaluated to the expression Start + 1, so use the is/2 operator.
You don't need the cut on the second clause, but on the first one.
Program:
create(X, X, [X]):- !.
create(Start, End, [Start|T]):-
Start =\= End,
Counter is Start + 1,
create(Counter, End, T).
Consult(You need the list to be instantiated, so use a variable instead of the empty list)
?- create(1,5, L).
L = [1, 2, 3, 4, 5].
In the first variant the base case is wrong:
create(_, 0, []).
Here the End argument is 0, but your non-base rule is never modifying the End, it is running on Start.
So your base case should match whenever Start is equal to the End:
create(E, E, []).
In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.