Get index of given element in list - prolog

I am trying to solve some basic puzzles to learn prolog. I am trying to get the index of a given element in a list with recursion. I got stuck trying to solve the problem and I am not sure why. When I execute this it only returns "false" instead of the index.
elem(_, [], 0).
elem(E, [E | T], RES) :-
elem(E, T, CUR_RES), RES is CUR_RES + 1.
An example query I use to check the code elem(2, [1, 2], X).

Your problem with
elem(2, [1, 2], X).
is that when it tries to unify with the base case
elem(_, [], 0).
it fails because the second parameter is not empty.
When it tries to unify with the recursive case
elem(E, [E | T], RES) :-
elem(E, T, CUR_RES),
RES is CUR_RES + 1.
E is 2, which requires the list to be [2|T] but since the list is [1,2] it also can not unify.
This is closer to what you want
elem(E,[E|_],0).
elem(E,[_|T],Res) :-
elem(E,T,Cur_rest),
Res is Cur_rest + 1.
Example runs:
?- elem(2, [1, 2], X).
X = 1 ;
false.
?- elem(1, [1, 2], X).
X = 0 ;
false.
?- elem(4, [1,2,3,4,5], X).
X = 3 ;
false.
You need to do the matching for the value you are seeking in the base case and not the recursive case. Once you do that the rest of changes follow as needed.

Related

Prolog check if list X has any duplicates

I have the function already but it is not working exactly as I want it to. The function I have is below..
isSet(List) :-
\+ (
select(Element, List, Tail),
select(Element, Tail, _)
).
When I do isSet([1,2,3]) it gives me true which is expected. When I do isSet([1,1,2]) it gives me false which is also what I expect and is correct. My question is how can I pass a list that is already made? For example If I do X = [1,2,3] and than pass it as a argument like isSet(X) it should give me true but instead it generates an error.
What can I do to fix this?
Edit:
?- [db].
true.
?- X = [1,2,3].
X = [1, 2, 3].
?- isSet(X).
false.
?- X = (1,2,3).
X = (1, 2, 3).
?- isSet(X).
false.
?- X = [1,1,2].
X = [1, 1, 2].
?- isSet(X).
false.
SWI-Prolog allows the form $Xs to access a variable from a previous query. E.g.:
?- Xs=[1,2,3].
Xs = [1, 2, 3].
?- isSet($Xs).
Xs = [1, 2, 3].
?- isSet([1|$Xs]).
false.
BTW, it's slightly more efficient to write your code like this (and I suggest using Rest rather than Tail: the latter is typically used in the form List=[Head|Tail]):
isSet(List) :-
\+ ( select(Element, List, Rest),
member(Element, Rest)
).
Also, you can't write a list like this: X = (1,2,3) ... that's actually something different:
?- write_canonical((1,2,3)), nl.
','(1,','(2,3))
true.
As there are discussions on how to best define the concept of "sets represented by lists", I humbly submit the following:
real_actual_set([]).
real_actual_set([X | Xs]) :-
nonmember_of(X, Xs),
real_actual_set(Xs).
nonmember_of(_X, []).
nonmember_of(X, [Y | Ys]) :-
dif(X, Y),
nonmember_of(X, Ys).
This is pure and works properly even in the presence of variables, including the most general query, and any lists containing variables that we would try to bind later:
?- real_actual_set([1, 2, 3]).
true .
?- real_actual_set([1, 1, 2]).
false.
?- real_actual_set([A, B, C]).
dif(A, C),
dif(A, B),
dif(B, C).
?- real_actual_set([A, A, B]).
false.
?- real_actual_set(Set).
Set = [] ;
Set = [_2222] ;
Set = [_2672, _2678],
dif(_2672, _2678) ;
Set = [_2970, _2976, _2982],
dif(_2970, _2982),
dif(_2970, _2976),
dif(_2976, _2982) ;
Set = [_3388, _3394, _3400, _3406],
dif(_3388, _3406),
dif(_3388, _3400),
dif(_3388, _3394),
dif(_3400, _3406),
dif(_3394, _3400),
dif(_3394, _3406) .
?- real_actual_set([A, B, C]), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.
?- real_actual_set([A, B, C]), A = 1, B = 1, C = 3.
false.
This is quadratic, so it's "less performant" than other approaches. But as John Ousterhout is quoted, "The best performance improvement is the transition from the nonworking state to the working state."
The correct way to check if a list is a set in Prolog is to sort it, removing duplicates, and check if its length is still the same. This is correct for all kinds of reasons, from very pragmatic (easy to program) to purely theoretic (it is the only robust approach to checking if a singly linked list is a set).
"But this is not what I asked" sure it isn't.
is_set(List) :-
sort(List, Sorted),
length(List, N),
length(Sorted, N).
Don't throw Bloom filters and the like at me, at least not without proper justification.
To address the comments by #IsabelleNewbie, if you really want to use attributed variables to make sure that a list will forever remain a set under unification, you would do:
all_different([]).
all_different([H|T]) :-
maplist(dif(H), T),
all_different(T).
but this is a different thing altogether. You also shouldn't use it unless you want to take a list with variables and make sure no two elements in this list will ever unify. You get answers like this (in SWI-Prolog):
?- all_different(X).
X = [] ;
X = [_] ;
X = [_A, _B],
dif(_A, _B) ;
X = [_A, _B, _C],
dif(_A, _B),
dif(_A, _C),
dif(_B, _C) ;
X = [_A, _B, _C, _D],
dif(_A, _B),
dif(_A, _D),
dif(_A, _C),
dif(_B, _D),
dif(_B, _C),
dif(_C, _D) .
I suspect you can find this code in other places too.
For example If I do X = [1,2,3] and than pass it as a argument like isSet(X) it should give me true but instead it generates an error.
You should show us exactly what you tried!
This works:
?- Xs = [1, 2, 3], isSet(Xs).
Xs = [1, 2, 3].
Note that both parts (binding Xs and testing it) are in one query. Maybe you tried entering them separately:
?- Xs = [1, 2, 3].
Xs = [1, 2, 3].
?- isSet(Xs).
false.
This doesn't work because the value of Xs is not saved from one query to the next. This still isn't an error, though. However, it is not great behavior because failing for isSet(Xs) seems to imply that no sets exist at all.

Prolog : Iterating over a list and creating a predicate

I'm creating a predicate enum that takes a list and a number for example [1,2,3,4] and 3 and returns a list that contains lists of length 3 made out of the list introduced. So in the example given enum([1,2,3,4],3,[[1,2,3],[2,3,4]]).
I've created a function take that takes only the first list of length N but I get errors when I try to loop it to get all of the others. Thanks you for helping.
append([],L,L).
append([H|T],L2,[H|L3]):- append(T,L2,L3).
len([],0).
len([_|B],X):- len(B,X1), X is X1+1.
take(_,X,Y) :- X =< 0, !, X =:= 0, Y = [].
take([],_,[]).
take([A|B],X,[A|C]):- Z is X-1, take(B,Z,C).
enum([],_,[]).
enum([N1|N2],N3,N4):-
len([N1|N2],U),
N3=<U,
take([N1|N2],N3,T1),
append([N4],[T1],T2),
!,
enum(N2,N3,T2).
I will focus on the take/3 predicate, which is the core of your question. In order to get a sublist like [2,3,4] of [1,2,3,4], you have to be able to skip the first element and just take a sublist of the rest.
You can achieve this by adding this clause to your definition:
take([_|Xs], N, Ys) :- take(Xs, N, Ys).
With this you now get several different sublists of length 3, but also some other superfluous solutions:
?- take([1,2,3,4], 3, Xs).
Xs = [1, 2, 3] ;
Xs = [1, 2, 4] ;
Xs = [1, 2] ;
Xs = [1, 3, 4] ;
Xs = [1, 3] ;
Xs = [1, 4] ;
Xs = [1] % etc.
This is because your clause take([], _, []) accepts an empty list as a "sublist of any length" of an empty list. I think you only wanted to accept the empty list as a sublist of length 0. If you remove this clause, your first clause will enforce that, and you only get solutions of length exactly 3:
?- take([1,2,3,4], 3, Xs).
Xs = [1, 2, 3] ;
Xs = [1, 2, 4] ;
Xs = [1, 3, 4] ;
Xs = [2, 3, 4] ;
false.
As a side note, your first clause is fine as is, but it can be simplified a bit to:
take(_,X,Y) :- X = 0, !, Y = [].
I would also advise you to use more readable variable names. For numbers like list lengths, we often use N. For lists, it's customary to use names like Xs, Ys, etc., with X, Y, etc. for members of the corresponding list.
Finally, to find all solutions of a predicate, you need to use a system predicate like setof, bagof, or findall. There is no way to write your enum in pure Prolog.
Because I am not sure about the advice in the other answer, here is my take on your problem.
First, don't define your own append/3 and length/2, append/3 is by now Prolog folklore, you can find it in textbooks 30 years old. And length/2 is really difficult to get right on your own, use the built-in.
Now: to take the first N elements at the front of a list L, you can say:
length(Front, N),
append(Front, _, L)
You create a list of the length you need, then use append/3 to split off this the front from the list you have.
With this in mind, it would be enough to define a predicate sliding_window/3:
sliding_window(L, N, [L]) :-
length(L, N).
sliding_window(L, N, [W|Ws]) :-
W = [_|_], % W should be at least one long
length(W, N),
append(W, _, L),
L = [_|L0],
sliding_window(L0, N, Ws).
This kind of works, but it will loop after giving you all useful answers:
?- sliding_window([a,b], N, Ws).
N = 2,
Ws = [[a, b]] ;
N = 1,
Ws = [[a], [b]] ;
% loops
It loops because of the same little snippet:
length(Front, N),
append(Front, _, L)
With length/2, you keep on generating lists of increasing length; once Front is longer than L, the append/3 fails, length/2 makes an even longer list, and so on forever.
One way out of this would be to use between/3 to constrain the length of the front. If you put it in its own predicate:
front_n(L, N, F) :-
length(L, Max),
between(1, Max, N),
length(F, N),
append(F, _, L).
With this:
sliding_window(L, N, [L]) :-
length(L, N).
sliding_window(L, N, [W|Ws]) :-
front_n(L, N, W),
L = [_|L0],
sliding_window(L0, N, Ws).
And now it finally works:
?- sliding_window([a,b,c,d], 3, Ws).
Ws = [[a, b, c], [b, c, d]] ;
false.
?- sliding_window([a,b,c], N, Ws).
N = 3,
Ws = [[a, b, c]] ;
N = 1,
Ws = [[a], [b], [c]] ;
N = 2,
Ws = [[a, b], [b, c]] ;
false.
Exercise: get rid of the harmless, but unnecessary choice point.

Deep Reverse in PROLOG - Lists

Hey I'm trying to create a predicate for the generating of a deep reverse on nested Lists in PROLOG.
Currently I got this predicate
reverse(L,A) :- rev(L,[], A).
rev([],A,A).
rev([H|L],R,A) :- rev(L,[H|R],A).
The result looks like this:
reverse([1,2,3],A).
A = [3, 2, 1].
reverse([[0,1],2,3],A).
A = [3, 2, [0, 1]].
The problem is, that the inner List is not reversed. It should look like this:
reverse([[0,1],2,3],A).
A = [3, 2, [1, 0]].
reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],A).
A = [12,11,[10,9],[8,[7,6],5,4,3],2,1].
Thanks for any help.
The way you represent your data is called defaulty, because you need a default case when reasoning over it:
is it a list? &rightarrow; something holds
otherwise &rightarrow; something else holds.
Such a representation is a rich source of troubles. Consider for example my_reverse/2 from the other answer. The main problem with it is that it prematurely and incorrectly commits to one of the cases, although both cases are still possible:
?- my_reverse([X], Ls).
Ls = [X].
But this answer only holds for the case where X is not a list! This problem leads to the following strange behaviour of the predicate:
?- my_reverse([X], Ls), X = [1,2,3].
Ls = [[1, 2, 3]],
X = [1, 2, 3].
This mean that even though X is a list, its elements are not reversed!
You should always aim for cleaner representations to distinguish the cases that can arise.
For example, what would you say about the following way to represent your data:
list(Ls) represents the list Ls
n(N) represents the number N.
With such a representations, we can distinguish the cases symbolically. I leave this as the starting point for a more declarative solution.
To keep things as simple as possible, we could add a test if the current element being checked is a list or not. If it is indeed a list, then its elements should be reversed as well. So in code:
my_reverse(L,R) :- rev(L,[],R).
rev([],A,A).
rev([H|T],A,R) :-
( is_list(H) -> % If H is a list
rev(H,[],X), % then reverse H as well
rev(T,[X|A],R)
;
rev(T,[H|A],R)
).
Also, not that it really matters, just to try and avoid confusion, note how I used A and R for respectively Accumulator and Result. In your code they are currently swapped, which -for me personally- can be a bit confusing, especially when predicates become longer and more complex.
Anyway, let's look at the queries you provided:
?- my_reverse([[0,1],2,3],R).
R = [3, 2, [1, 0]].
?- my_reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],R).
R = [12, 11, [10, 9], [8, [7, 6], 5, 4, 3], 2, 1].
And some general queries:
?- my_reverse(L,R).
L = R, R = [] ;
L = R, R = [_G2437] ;
L = [_G2437, _G2443],
R = [_G2443, _G2437] ;
L = [_G2437, _G2443, _G2449],
R = [_G2449, _G2443, _G2437] ;
L = [_G2437, _G2443, _G2449, _G2455],
R = [_G2455, _G2449, _G2443, _G2437]
...
?- my_reverse([[X,Y]|T],R), member(a,T), length(X,2).
X = [_G2588, _G2591],
T = [a],
R = [a, [Y, [_G2588, _G2591]]]
;
X = [_G2594, _G2597],
T = [a, _G2588],
R = [_G2588, a, [Y, [_G2594, _G2597]]]
;
X = [_G2594, _G2597],
T = [_G2582, a],
R = [a, _G2582, [Y, [_G2594, _G2597]]]
...
Note however that using this predicate, no termination occurs after finding the first answer to the query:
?- my_reverse(X,[X]).
X = [X] ;
...
But since this wasn't a requirement/demand in OP's question, I assumed it to be okay.
EDIT:
Please read #mat's answer as a follow-up to this problem.
an additional solution for your problem is to use cut and the built-in predicate "is_list/1" to check if you treat a simple term or a list in the current call.
here is the code:
deepReverse(List,R):-deepReverseTail(List,[],R).
deepReverseTail([],Acc,Acc).
deepReverseTail([H|T],Acc,R):- % when H is a list
is_list(H), % check if it's a list.
!, % cut the process if not.
deepReverseTail(H,[],Hrev), % reverse this current list
deepReverseTail(T,[Hrev|Acc],R). % continue the general recursion
deepReverseTail([H|T],Acc,R):- deepReverseTail(T,[H|Acc],R). % when H is a simple term
the "cut" in the third line make sure you treat only list in this definition, while treating simple terms will be in the next definitions.
an output example:
7 ?- deepReverse([a,[d,f],[],[[k],g]],R)
R = [[g, [k]], [], [f, d], a].

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 - outputting a list?

I have the function
sublist(_,[_],_) :-
!.
sublist(X,[Y|T],Z) :-
R is X - Y,
sublist(X,T,[R|Z]).
an example call is sublist(2,[1,2,3],Z).
At the end of execution it just gives me 'yes', but i'd like to see the contents of Z.
I know it's something simple as i have other instructions that do similar things, but this one isn't working.
I'm also going to assume that sublist/3 is supposed to subtract a number from all items in the list.
The reason you're not getting any result for Z is because you're building the list on the way into the recursion. Which means that when the stopping predicate succeeds, Prolog works it's way back out of the recursion and Z becomes uninstantiated again.
Z is ?
|
Z is [-1]
|
Z is [-1, 0]
|
Z is [-1, 0, 1]
|
Z is [-1, 0]
|
Z is [-1]
|
Z is ?
Try going into the recursion first and building your list on the way out. Maybe like this:
subtract_list(_, [], []).
subtract_list(Number, [Head|Tail], [Subtracted|Result]):-
subtract_list(Number, Tail, Result),
Subtracted is Head - Number.
All we've changed is the order of the rules in the recursive predicate and the terms of the stopping condition. Now it recurses until it reaches an empty list, at which point it instantiates the result variable with an empty list as well. Then it bubbles back up adding values to the list as it does so.
?- subtract_list(1,[4,3,2],Z).
Z = [3, 2, 1]
Hope this helps. Tom
You don't really specify what sublist/3 is supposed to do but maybe you mean this:
sublist(_, [], []) :- !.
sublist(X, [Y | T], [R | Z]) :-
R is X - Y,
sublist(X, T, Z).
Usage example:
?- sublist(2, [1, 2, 3], Z).
Z = [1, 0, -1].
Btw, if you don't want to iterate over the list yourself, then you can use maplist/3 which is provided by SWI-Prolog. First define your desired calculation:
my_calculation(X, Y, Z) :-
Z is X - Y.
and then call maplist/3:
?- maplist(my_calculation(2), [1, 2, 3], Z).
Z = [1, 0, -1].

Resources