Prolog. Does not create a list - prolog

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, []).

Related

I need to multiply and sum one list, the output should be like this

I need to multiply and sum one list, the output should be like this:
?- tp4([1,7,0,1,2,3,5], L).
L = [210,19,1,7,0,1,2,3,5]
First the multi, next the sum and at the end the rest of the numbers.
Here is a builing brick answer to your question since you seem to have a "where to start" problem. It is important to learn it by yourself, therefore you can conclude the correct answer by using maplist/2 and fold/4 as mentioned from David Tonhofer. But these are "advanced" predicates, so lets start from scratch and implement the base functionalities.
First: how to append elements to a list. You can either put something as a head of a list ([Head|List]) or use the predicate append/2 (which is build in but you can easily implement it by yourself). Note that variables start with a capital letter.
?- List=[1,2,3,4], Head = 0, Out=[Head|List].
Head = 0,
List = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
?- List2=[1,2,3,4], List1 = [0], append(List1,List2,Out).
List1 = [0],
List2 = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
You are be able to add elements to a list.
If you want to implement your own predicate, which works on lists, you either use the inbuild predicates or implement it yourself. We'll do the second one for the example of subtraction (all elements are subtracted from the last element).
Our predicate subtract/2 needs 2 attributes: a list (input) and a "return" value (output).
If the list has only one element ([H]), return the element. Otherwise split the list into a Head element and a Rest list ([Head|Rest]), compute the substract value for the list Rest (Tmp) and subtract Head from it:
subtract([H],[H]).
subtract([Head|Rest], Sub):-
subtract(Rest,Tmp),
Sub is Tmp - Head.
Test:
?- subtract([1,2,3,10],O).
O = 4 ;
false.
Works, not perfect but works. Now you know how to add elements to a list and have an example how to build predicated which operate on lists and use arithemtic functions. Now you can build your desired function.
You need to walk the list and compute the product and sum as you go from element to element. Given the neutral elements of the product and sum are, respectively, 1 and 0:
product_sum_list([Head| Tail], [Product, Sum, Head| Tail]) :-
product_sum_list(Tail, Head, 1, Product, 0, Sum).
Note that we're requiring the list to have at least one element. The auxiliary product_sum_list/6 performs the actual computation of the product and sum:
product_sum_list([], Last, Product0, Product, Sum0, Sum) :-
Product is Product0 * Last,
Sum is Sum0 + Last.
product_sum_list([Next| Tail], Current, Product0, Product, Sum0, Sum) :-
Product1 is Product0 * Current,
Sum1 is Sum0 + Current,
product_sum_list(Tail, Next, Product1, Product, Sum1, Sum).
By splitting the list between its head tail moving the tail to the first argument of the auxiliary predicate, we take advantage of the first argument indexing provided by the generality of Prolog systems to avoid the creation of spurious choice-points.
Sample call:
| ?- product_sum_list([1,7,0,1,2,3,5], L).
L = [0,19,1,7,0,1,2,3,5]
yes
You can achieve the same results using, as David suggested, meta-predicates for mapping and folding lists. But given that we need to compute both product and sum, the straight-forward solution is simpler and more efficient.
A common Prolog idiom is the use of a helper predicate, that takes extra arguments that maintain state. These also help you get to tail recursion so as to not consume stack.
The naive way to multiply a list might be:
multiply( [] , 0 ) . % The empty list has a product of zero.
multiply( [P] , P ) . % A list of length 1 is the value of the singleton element.
multiply( [N|Ns] , P ) :- % To compute the product of a list of length > 1...
multiply(Ns,T), % - recursively multiply the tail of the list, then
P is N * T % - multiply the head by the product of the tail
. % Easy!
Summation would be pretty much identical save for the operation involved.
[Note: given a list of sufficient length, this would eventually fail due to a stack overflow.]
Using a helper predicate (1) makes it tail recursive, meaning it won't blow up and die on a long list, and (2) will facilitate combining summation and multiplication. The 'helper' implementation looks like this:
multiply( [] , 0 ) .
multiply( [N|Ns] , P ) :- multiply(Ns,N,P).
multiply( [] , P , P ) .
multiply( [N|Ns] , T , P ) :-
T1 is T * N ,
multiply( Ns, T1, P )
.
And summation, again, is pretty much identical.
Now we can combine them to get what you want:
multiply_and_sum( [] , [0,0] ) .
multiply_and_sum( [N|Ns] , [P,S|Ns] ) :-
multiply_and_sum( Ns, N, N, P, S )
.
multiply_and_sum( [] , P, S, P, S ) .
multiply_and_sum( [N|Ns] , X, Y, P, S ) :-
X1 is X * N,
Y1 is Y + N,
multiply_and_sum( Ns, X1, Y1, P , S )
.

Finding unique permutations of a list in gprolog

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.

Using a functor

Following code accepts a index , a list and it deletes every nth occurance of that index in the list and returns a new list.
deleteNTerm(N,L1,L2) :- deleteNTerm(L1,N,L2,N).
deleteNTerm([],_,[],_).
deleteNTerm([_|Xs],N,Ys,1) :- deleteNTerm(Xs,N,Ys,N).
deleteNTerm([X|Xs],N,[X|Ys],K) :- K > 1, K1 is K - 1, deleteNTerm(Xs,N,Ys,K1).
So for the following query
?- deleteNTerm(2,[1,2,3,4,5,6,7],Result).
Result = [1,3,5,7].
However I want my code to accept a functor instead so i get
?-deleteNterm(2,f(1,2,3,4,5,6,7),Result).
Result f(1,3,5,7)
How to achieve this?.
You can break down a term into its functor and arguments using the (appropriately named) predicate functor. This being prolog, it is also used to build a term from those components. For example: functor(A,f,3) will yield A = f(_G2130, _G2131, _G2132).
Actually, what would be more helpful would be =..:
3 ?- f(1,3,5,7) =.. X.
X = [f, 1, 3, 5, 7].
4 ?- X =.. [f,1,3,5,7].
X = f(1, 3, 5, 7).

Prolog print array fails

I'm fairly new to Prolog, and I'm having the following issue:
I represent a two-dimensional array as follows:
[[ROW1], [ROW2],..]
I wrote a predicate to print out the two dimensional array as follows:
valueAt(1, [BEGIN | _], BEGIN).
valueAt(POSITION, [FIRST | REST], VAL) :- NPOS is POSITION - 1,
valueAt(NPOS, REST, VAL).
printRowValues([], _).
printRowValues(ROW, STARTIDX) :- valueAt(STARTIDX, ROW, VALUE),
print(VALUE), print(' '),
NEXTIDX is STARTIDX + 1,
printRowValues(ROW, NEXTIDX).
printContainer(CONTAINER) :- printRows(CONTAINER, 1).
printRows([]).
printRows([ROW | REST]) :- printRowValues(ROW, 1),
printRows(REST).
This prints the first row and then just gives false. I don't really see my problem here..
PS: The function printRowValues uses the index because I used it to test my valueAt function. I know I can write the printrow function much simpler (see below) but that's not the point. I'm missing some Prolog knowledge here.
Simpler version that makes the entire thing work:
printRow([]).
printRow([HEAD | REST]) :- print(HEAD), print(' '),
printRow(REST).
Sample query:
[debug] [1] 41 ?- printRows([[1, 1, 1], [2, 2, 2], [3, 3, 3]]).
1 1 1
false
The problem with your implementation is that the first (base) clause of the printRowValues is never reached, because the second clause does not reduce the list to make it shorter. It is the same list that is always passed, so Prolog interpreter never reaches the base clause.
You can fix this by changing the base clause to use len/1 predicate:
printRowValues(List, N) :- N is 1 + len(List).
This will terminate once N reaches the length of the list plus one (you need plus one because your indexes are one-based).

Prolog Clear List of negative elements without using cuts

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

Resources