Getting unbound list tail in Prolog - prolog

I'm trying to write a predicate that will take a list, a number, and a variable that will then give the first N elements of the list to the variable. I'm able to do this, but while trying to make it more flexible so that it will stop when it reaches the end of the list or when N is 0, I started getting a garbage variable returned at the end of my list.
Here is my code:
take(_,0,_) :- !.
take([],_,_) :- !.
take([Head|Tail], Number, [Head|Result]) :-
Number > 0,
N1 is Number - 1,
take(Tail, N1, Result).
and when I try to use take([1,3,5,7], 3, L1), I get L1 = [1, 3, 5|_G2028].
I think it has something to do with how I didn't define Result as an empty list, but I don't know how to do so, while keeping the functionality of the predicate.

Change the first 2 rules to:
take(_,0,[]) :- !.
take([],_,[]) :- !.
From your code I can see that take is a predicate that returns true when the 3rd argument is the result of taking the leading elements from the list in the first argument as many as possible but less than the number specified 2nd argument.
So you can constraint the output when 2nd argument is 0 to [], since you have reached the limit.
And you can constraint the output when the 1st argument is an empty list to [], since you can't take anything anyway.
Without the constraints above, it means that anything is valid when the maximum number of elements to take is 0 or when the original list is empty.
Alternatively, you can write everything in one rule:
take(In, Num, Out) :- append(Out, _, In),
length(Out, OutLen), length(In, InLen),
OutLen is min(Num, InLen), !.
The length of the output list is the minimum between the length of original list and Num, that is used as constraint to the append to take out exactly the appropriate number of elements from the original list.

While the existing answer tells you how to fix it, I'd like to try to explain what that "garbage variable" is.
I get L1 = [1, 3, 5|_G2028].
That variable in your list, _G2028, is an uninstantiated variable. The interpreter knows that something is there, but doesn't know what the something is.
This is happening because of the first two clauses,
take(_,0,_) :- !.
take([],_,_) :- !.
The first one says, paraphrased, if you take 0 items from anything, you can get anything.
The second one says, if you take any number of items from an empty list, you can get anything.
So the interpreter gets to one of these, because it wanted to evaluate take(Tail, N1, Result). At that point, Tail is known, N1 is known, but Result is yet unknown. After calling either of these clauses, the interpreter is none the wiser, since neither tells it what Result is. But the goal succeeded, so it reports back and tells you that L1 = [1, 3, 5|_G2028].

Related

Why am I getting Type error: `[]' expected, found `[21,3,4,5,6,7,8]' (a list) ("x" must hold one character) with maplist/3 prolog?

I am new to Prolog. I want a predicate that takes a list, process it with maplist/3 creating a corresponding list with zeros in place of numbers less than mean and 1 for number above the mean. I then want a second predicate to sum the 1's to find out how many numbers are above the mean. This second predicate then returns this number which corresponds to total numbers above the mean.
I know the code below works fine:
numAtOrAboveMean(Mean, Num, Val) :- Num > Mean -> Val is 1; Val is 0.
maplist(numAtOrAboveMean(Mean), [], List), sumlist(List, Below).
When I modified it to this, I get a type erros that expected [] but found a list. The comments correspond to how I think the predicate behavior is.
nGMean(Mean, Num, Val) :- Num > Mean -> Val is 1; Val is 0.%sorts list
nGMean([], _ , []). %takes a list, a constant, relates to a list
nGMean(L, Mean, List) : - maplist(nGMean(Mean), L, List). %maplist call sort
Then to sum I will use a second predicate. Something like this:
sumtotal(L,V) :- mean(L, M), M2 is M, nGMean(L, M2, List), sum(List, V).
Which is not working probably mostly because nGMean is throwing an error. nGMean full error is shown below:
So my question is, why am I getting that type error on the nGMean predicate?
Edit -As requested in comments below is the entire thing. As I explained that is the only part because I am testing it separately.
Thank you for answers. Next time I will post complete code.Or make clear that I just want to trouble shoot one predicate.
Maplist for numAtOrAboveMean
Full Pic of code on Editor
You should post complete code that can just be copied and run. In what you have posted, mean/2 and sum/2 are not defined.
(Addition:) the reason for the error seems to be that you are comparing a value and a list (2<[2,3|...]). The reason this happens is because your first clause for nGMean/3 has Mean as first parameter, whereas the other clauses has the list, i.e. the list becomes Mean which is used in the comparison (Num > Mean). I'm not sure how > becomes <.
Also, calling maplist/3 on an empty list does not make sense.
A recursive predicate should have two clauses. A recursive clause that (typically) does something with the head of the list and then calls recursively on the tail, and a base case (empty list).
nGMean([Num|Nums],Mean,[Val|List]) :-
( Num > Mean ->
Val = 1
; Val = 0 ),
nGMean(Nums,Mean,List).
nGMean([],_,[]).
With this definition I get the same output as your first two lines above, so I believe this is what you wanted.
(Earlier addition: you only need to use is when the right-hand side contains mathematical calculations. To just set a value, = is fine.)

Prolog - Domain error: 'acyclic_term ' expected

What I have to do is, write a predicate Multiplication/3, whose first argument is an integer, second argument is a list, and the third argument is the result of multiplying the integer with the list, for example:
?-Multiplication(3,[2,7,4],Result).
should return
Result = [6,21,12].
Here's my code:
Multiplication(X,[],Result).
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
And I get the following error:
Domain error: 'acyclic_term ' expected, found '#(lists:append([],S_1,S_1),[S_1=[S_1,1]])'
on the second append call.
If anyone knows why I receive the error, how to fix it or another way to solve this, I'm open to ideas.
Your two goals append([Result], [Y], L), append([],L,Result) are exactly the same as:
L = [Result,Y], L = Result.
or even simpler:
L = [L,Y]
which would result either in silent failure or an infinite term. Instead, your Prolog produces an error, so that you can correct your program.
In your original code:
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
You're getting a "cycle" because you're appending Result to something to get L, then appending something to L to get Result. That's not good. You also have a capitalized predicate name, which is a syntax error. (I assume that, since you ran your code, it wasn't capitalized in the original version.)
You're new proposed solution is overly complicated. Why do you need the 4th argument? Also, your base case for return (which is return(X, [], Result) doesn't make sense, as it has to singleton variables. The use of append/3 is overkill since recursion handles the iteration through the list elements for you.
Starting from the top, you have a common pattern in Prolog where you want to run a query on corresponding elements of two or more lists. A simple recursive solution would look something like this:
multiplication(_, [], []). % Multiplying anything by the empty list is the empty list
multiplication(M, [X|Xs], [XX|XXs]) :-
XX is M * X,
multiplication(M, Xs, XXs).
Another way to implement this kind of pattern in Prolog is with maplist/3. You can first define the query on corresponding elements:
multiply(X, Y, Product) :- Product is X * Y.
Then use maplist/3:
multiplication(M, List, Result) :-
maplist(multiply(M), List, Result).
Maplist will do a call(multiply(M), ...) on each corresponding pair of elements of List and Result.
I edited the code and came up with this:
multiplication(X,[],Result,Result).
multiplication(X,[Head|Tail],List,Result) :-
Y is X*Head,
append(List, [Y], L),
multiplication(X,Tail,L,Result).
return(X,[],Result).
return(X,L,Result) :-
multiplication(X,L,_,Result).
and the query:
return(2,[1,2],Result).
After the first run, it seems to return Result as it should be, but it runs forever.

Prolog - Comparing Lists that have the same element on the same index

I've been working on Prolog for a few weeks right now. I am now trying to write a function in it called matching:
Write a predicate called matching with three parameters, all lists.
The third list must contain the index of the positions in which
the first two lists contain the same value.
If I run
matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
The results are:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [] ;
Positions = [] ;
Positions = [_2420] ;
Positions = [_2420] ;
Positions = [_2420, _2432];...
The correct answer would be that Positions is bound to [1,3]. I have no idea what is wrong with my code. Any hint is appreciated.
A hint? Each of your matchingHelper clauses contains a mistake!
OK, a little more than a hint:
Base cases
Prolog should be giving you a warning about singleton variables here. ListofIndex is a variable, but it is only used in one place. Essentially this means that there is absolutely no constraint on this, and thus can be anything.
The correct thing would be that if either of the input lists is empty, the output is also empty.
matchingHelper([], _, , []).
matchingHelper(, [], _, []).
Equal case
This one you almost have correct, but the way you deal with ListOfIndex is backwards. You construct a NewListOfIndex based on the predicate arguments, and use that in the recursive call. The problem is that the ListOfIndex is actually the output! So you should instead construct the ListOfIndex based on the output from the recursive call.
matchingHelper([X|Xs], [X|Ys], Index, [Index|ListofIndex]) :-
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Unequal case
Just 2 little issues with this one. First is that this clause should only apply if X and Y are different. Just using a different variable name does not enforce this. Because there is a previous clause which handles the equal case, the first result prolog finds would be correct, but it will continue to find other, incorrect solutions because of this.
The second issue is that you don't increment the index. If you ignore the first element, the current index has to be incremented to reflect the current position.
matchingHelper([X|Xs], [Y|Ys], Index, ListofIndex) :-
X \= Y,
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Here's a sample run:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [1, 3]
false

Generating a list in prolog

Hello I want to make a program in Prolog, that given a list of numbers and a number, it appends all the concurences of position of the number in a second list.
For example for the list (5,10,4,5,6,5) and number =5 the new list should be
(1,4,6)
here is my code so far
positions(X, [X|_],1).
positions(X, [P|T], N) :- positions(X, T, N1), N is N1+1.
find(X, [H|T] ,Z) :-positions(X,[H|T],N) , append([],N,Z).
the positions returns the first concurrence of X in the list, but I don't know how to proceed. Can you help me?
If it's not an assignment, then you can benefit from using the built-ins findall/3 and nth1/3:
?- findall(Nth, nth1(Nth, [5,10,4,5,6,5], 5), Nths).
Nths = [1, 4, 6].
Taking just the nth1 phrase, and running that, you can see it is backtracking and finding multiple solutions, then we just use findall to collect them into a list.
?- nth1(Nth, [5,10,4,5,6,5], 5).
Nth = 1 ;
Nth = 4 ;
Nth = 6.
nth1/3, when using a variable for the first parameter, is saying 'give me a list index where where the 3rd parameter is found in the list of the second parameter.
You have some good ideas, but I would suggest a couple things:
1) In Prolog, it can be beneficial to give variables meaningful names
2) Use an accumulator and you will only need positions and append
3)Use a different base case
positions([Num|List],Num,[Index|SubResult],Index) :- Index2 is Index+1,
positions(List,Num,SubResult,Index2).
positions([NotNum|List],Num,Result,Index) :- NotNum \= Num,
Index2 is Index+1,
positions(List,Num,Result,Index2).
positions([],Num,[],Index).
In our first general case, we can see the numbers match, so we go find how many results are in our sublist, which we will call the SubResult and then push the current index on to our SubResult
The next general case, the numbers do not unify, and our Result IS the SubResult, so let's call them the same thing.
In our final case (the base case) we can see the list is empty, in this case we return an empty list as we cannot match against an empty list.
You can see that the above rules are order-independent, which is something very valuable in Prolog. This means you can arrange the rules in any order, and the semantics of your Prolog program remain unchanged. Using unification to achieve this will prevent future pain in debugging.
We can wrap our predicate in the following way
positions(Num, List, Positions) :- positions(List, Num, Positions, 1).
This will allow for queries of positions(5,[5,10,4,5,6,5],Positions).

Prolog -how to implement a nested function in prolog?

I need to write rules below:
Write the rules for a predicate take(L,N,L1), which succeeds if list L1 contains the
first N elements of list L, in the same order. The following queries show examples of using this predicate:
?- take([5,1,2,7], 3, L1).
L1 = [5,1,2]
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7]
My idea is to delete the first number of two list any time until L1 is empty.
I am also thinking that I can use car([X|_], X) to delete the last number each time until the first list ==the second list. I already wrote the length(L,Len), but I don't know how to do next...
My code is:
take(L,X,[]).(I know it miss something, but I don't know how to do...)
take(H|L,N,H|L1):- take(L,X,L1), N is X-1.
=========================Update=================================================
Thank you 1638891!
Right now, the code is
take(L,0,[]).
take([H|L],N,[H|L1]):- take(L,X,L1), N is X+1.
But it doesn't work in the second case, which is
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7]
I tried to add
take([],X,[])->!.
But it pop up "ERROR: is/2: Arguments are not sufficiently instantiated".
#user1638891 forgot to swap the subtraction, and to cover the case when you are requested more elements than available:
take(_,0,[]).
take([],_,[]).
take([H|L],N,[H|L1]) :- N > 0, X is N-1, take(L,X,L1).
You actually want to write X is N - 1.
take(L,0,[]).
take([H|L],N,[H|L1]):- take(L,X,L1), X is N-1.
As a general rule try to read your rules aloud. The first rule you wrote reads as "Empty list is the list with the first X elements in L." But it should have been "Empty list is the list with the first 0 elements in L" as a base case.

Resources