Prolog Array Pipe Meaning - syntax

Can anybody explain the following code? I know it returns true if X is left of Y but I do not understand the stuff with the pipe, underscore and R. Does it mean all other elements of the array except X and Y?
left(X,Y,[X,Y|_]).
left(X,Y,[_|R]) :- left(X,Y,R).

If you are ever unsure about what a term "actually" denotes, you can use write_canonical/1 to obtain its canonical representation.
For example:
| ?- write_canonical([X,Y|_]).
'.'(_16,'.'(_17,_18))
and also:
| ?- write_canonical([a,b|c]).
'.'(a,'.'(b,c))
and in particular:
| ?- write_canonical([a|b]).
'.'(a,b)
This shows you that [a|b] is the term '.'(a,b), i.e., a term with functor . and two arguments.
To reinforce this point:
| ?- [a|b] == '.'(a,b).
yes

#mat answered the original question posted quite precisely and completely. However, it seems you have a bigger question, asked in the comment, about "What does the predicate definition mean?"
Your predicate, left(X, Y, L), defines a relation between two values, X and Y, and a list, L. This predicate is true (a query succeeds) if X is immediately left of Y in the list L.
There are two ways this can be true. One is that the first two elements in the list are X and Y. Thus, your first clause reads:
left(X, Y, [X,Y|_]).
This says that X is immediately left of Y in the list [X,Y|_]. Note that we do not care what the tail of the list is, as it's irrelevant in this case, so we use _. You could use R here (or any other variable name) and write it as left(X, Y, [X,Y|R]). and it would function properly. However, you would get a singleton variable warning because you used R only once without any other references to it. The warning appears since, in some cases, this might mean you have done this by mistake. Also note that [X,Y|_] is a list of at least two elements, so you can't just leave out _ and write [X,Y] which is a list of exactly two elements.
The above clause is not the only case for X to be immediately left of Y in the list. What if they are not the first two elements in the list? You can include another rule which says that X is immediately left of Y in a list if X is immediately left of Y in the tail of the list. This, along with the base case above, will cover all the possibilities and gives a complete recursive definition of left/3:
left(X, Y, [_|R]) :- left(X, Y, R).
Here, the list is [_|R] and the tail of the list is R.

This is about the pattern matching and about the execution mechanism of Prolog, which is built around the pattern matching.
Consider this:
1 ?- [user].
|: prove(T):- T = left(X,Y,[X,Y|_]).
|: prove(T):- T = left(X,Y,[_|R]), prove( left(X,Y,R) ).
|:
|: ^Z
true.
Here prove/1 emulates the Prolog workings proving a query T about your left/3 predicate.
A query is proven by matching it against a head of a rule, and proving that rule's body under the resulting substitution.
An empty body is considered proven right away, naturally.
prove(T):- T = left(X,Y,[X,Y|_]). encodes, "match the first rule's head. There's no body, so if the matching has succeeded, we're done."
prove(T):- T = left(X,Y,[_|R]), prove( left(X,Y,R) ). encodes, "match the second rule's head, and if successful, prove its body under the resulting substitution (which is implicit)".
Prolog's unification, =, performs the pattern matching whilst instantiating any logical variables found inside the terms being matched, according to what's being matched.
Thus we observe,
2 ?- prove( left( a,b,[x,a,b,c])).
true ;
false.
3 ?- prove( left( a,b,[x,a,j,b,c])).
false.
4 ?- prove( left( a,b,[x,a,b,a,b,c])).
true ;
true ;
false.
5 ?- prove( left( a,B,[x,a,b,a,b,c])).
B = b ;
B = b ;
false.
6 ?- prove( left( b,C,[x,a,b,a,b,c])).
C = a ;
C = c ;
false.
The ; is the key that we press to request the next solution from Prolog (while the Prolog pauses, awaiting our command).

Related

Prolog predicate that extracts all words immediately following a word in a given list of words

As it says in the title, i need to get all the words after a specifc word in prolog, for example:
?- find([in, house, car, in, shop, no, more, apples, in, table], in , X).
X = [house, shop, table] ;
No
This is the code i've written so far:
find([H,H_1|_],H,[H_1]).
find([Head,Head_1|Tail], Term, [Head|Result]) :-
find(Tail, Term, Result).
After i run it, i get:
X = [house] ;
X = [in, car, shop, more, table] ;
No
There is nothing better than writing simple programs to learn a language. After you grasp the basics, you could be interested into more idiomatic approach:
find(L,W,Fs) :- findall(F, append(_,[W,F|_],L), Fs).
The main problem is probably located here:
find([H,H_1|_],H,[H_1]).
This code unifies the list with the first element after the match. You then unify the third parameter (which is here used as a "result") with a list containing the single occurrence.
Note furthermore that it is also possible that we reached the end of the list. So in that case the predicate will fail as well.
Basically there are four cases here:
we reach the end of the list, the "result" parameter should unify with the empty list;
we found the element and there is a next element (that is also a match), we perform one step and continue our search;
we found the element and there is a next element (that is not a match), we add that element and continue our search;
the head does not match, we continue our search.
We can implement these possibilities as:
find([],_,[]). % we reach the end of the list
find([H,H|T],H,T2) :- % there is a match, the successor is also a match
find([H|T],H,T2). % perform one hop
find([H,N|T],H,[N|T2]) :- % there is a match, add the next element
N \= H,
find(T,H,T2). % and continue
find([N|T],H,T2) :- % there is no match
N \= H,
find(T,H,T2). % we continue
This produces:
?- find([in, house, car, in, shop, no, more, apples, in, table], in , X).
X = [house, shop, table] ;
false.
?- find([a,b,c],c,X).
false.
?- find([a,b,c,a,d],a,X).
X = [b, d] ;
false.
?- find([a,a,b],a,X).
X = [b] ;
false.
(Yes/No are in swi-prolog true/false).

Predicate about a list of lists

I'm trying to create a predicate that receives a list of lists and returns a list of lists containing all the unitary lists (lists whose length is 1) from the first list, however it is not working. This is what I created:
elimina_listas_nao_unitarias_lista_de_listas([[A]|T],N_List):-
length([A], 1),
N_List is [H|N_List_T],
elimina_listas_nao_unitarias_lista_de_listas(T, N_List_T).
elimina_listas_nao_unitarias_lista_de_listas([[A]|T], N_List):-
length([A], X),
X > 1,
elimina_listas_nao_unitarias_lista_de_listas(T, N_List2).
Thi is what it should do:
elimina_listas_nao_unitarias_lista_de_listas([[1,2],[1,2,3],[3]], [3])
elimina_listas_nao_unitarias_lista_de_listas([[1,2],[1,2,3],[3,4,5]], [])
It is retuning false currently everytime
Let's take a look at your first rule. The first goal always succeeds, since you are asking if a list with a single element is of length 1. Just try it at the prompt:
?- length([A], 1).
true
Instead, you probably want to have a variable without the brackets in the head of the first list (e.g. [L|Ls]) and ensure that it is a list of length 1:
?- length(L,1).
L = [_A]
The same goes for the first list in the head of your second rule and its first goal. In your second goal you are trying to evaluate [H|N_List_T] as an arithmetic expression with is/2 such that N_List holds the value. Besides the fact that this doesn't make sense, you can try that at the prompt and see how this goal can't succeed:
?- N_List is [H|N_List_T].
ERROR!!
TYPE ERROR- string must contain a single character to be evaluated as an arithmetic expression: expected evaluable term, got [_131245|_131246]
Instead, you want to unify the two terms:
?- N_List = [H|N_List_T].
N_List = [H|N_List_T]
However, you can get rid of this goal entirely if you write [H|N_List_T] as the second argument in the head of the rule. Additionally, you might want the unitary list L in the head of the second list instead of the variable H. Furthermore you are missing a case, namely the first list being []. In that case the second list is empty as well, since the empty list clearly does not contain any unitary lists. Finally, I would note that it might enhance the readability of your code if you picked a somewhat simpler and more declarative name, say listas_unitarias/2. Putting all this together, you might end up with a predicate like this:
listas_unitarias([],[]).
listas_unitarias([L|Ls],[L|Ss]) :-
length(L,1),
listas_unitarias(Ls,Ss).
listas_unitarias([L|Ls],Ss) :-
length(L,X),
dif(X,1),
listas_unitarias(Ls,Ss).
Your second example query yields the desired result
?- listas_unitarias([[1,2],[1,2,3],[3,4,5]],U).
U = []
For your first example query the result is slightly different:
?- listas_unitarias([[1,2],[1,2,3],[3]], U).
U = [[3]] ? ;
no
The only unitary list is in a list itself. That would make more sense, since the first argument might contain more than one such list. Consider the following case:
?- listas_unitarias([[1],[2,3],[4],[]],U).
U = [[1],[4]] ? ;
no
However, if you meant to get the unitary lists one at a time, the predicate would look slightly different:
listas_unitarias2([L|_Ls],L) :-
length(L,1).
listas_unitarias2([_L|Ls],U) :-
listas_unitarias2(Ls,U).
As would the results of the queries:
?- listas_unitarias2([[1,2],[1,2,3],[3]], U).
U = [3] ? ;
no
?- listas_unitarias2([[1],[2,3],[4],[]],U).
U = [1] ? ;
U = [4] ? ;
no
Especially your second example query: It would fail instead of producing the empty list as a solution:
?- listas_unitarias2([[1,2],[1,2,3],[3,4,5]],U).
no
?- listas_unitarias2([[1,2],[1,2,3],[3,4,5]],[]).
no
EDIT: As pointed out by #false in the comments the combined use of length/2 and dif/2 in the third rule doesn't terminate for [_,_|_] so the query
?- listas_unitarias([[1],[_,_|_],[2],[3,4]],U).
U = [[1],[2]] ? ;
U = [[1],[2]] ? ;
...
does not terminate as well. However, it is reasonable to expect termination in this case, since a list headed by two elements certainly can't be unitary. So, instead of using length/2 you might consider describing the four cases that cover all possibilities. 1) If the first list is empty so is the second list. 2) If the head of the first list is [] it's not in the second list. 3) If the head of the first list is [A] it is in the second list. 4) If the head of the first list has at least two elements it's not in the second list.
listas_unitarias([],[]). % case 1)
listas_unitarias([[]|Ls],Ss) :- % case 2)
listas_unitarias(Ls,Ss).
listas_unitarias([[A]|Ls],[[A]|Ss]) :- % case 3)
listas_unitarias(Ls,Ss).
listas_unitarias([[_,_|_]|Ls],Ss) :- % case 4)
listas_unitarias(Ls,Ss).
With this version the above query terminates after finding the only solution:
?- listas_unitarias([[1],[_,_|_],[2],[3,4]],U).
U = [[1],[2]]
The other queries from above yield the same results:
?- listas_unitarias([[1,2],[1,2,3],[3,4,5]],U).
U = []
?- listas_unitarias([[1,2],[1,2,3],[3]], U).
U = [[3]]
?- listas_unitarias([[1],[2,3],[4],[]],S).
S = [[1],[4]]

Set Intersection predicate Prolog using not

I am trying to build a simple predicate which get as inputs two lists and the results is a third one consisting of the intersection of the first two.
I have decided to do using logical statement. I am pretty sure my logic is correct but my predicate is not working. Any ideas?:
element(X,[H|T]) :-
X=H
;
element(X,T).
intersection(L1,L2,R) :-
not((
element(A,L1),
not(element(A,L2))
)),
not((
element(A,L1),
not(element(A,R))
)).
Please do not post alternative methods I am wondering why this one returns FALSE every time.
Your definition is correct too general. It admits e.g. that [] is the intersection of any two lists which is too general. I.e. it incorrectly succeeds for intersection([],[a],[a]). It lacks a third "for all" idiom stating that all elements that are in both lists will be in the resulting list.
But otherwise your definition is fine. For the ground case. What is a bit unusual is that the intersection is the first and not the last argument. Quite irritating to me are the variable names. I believe that R means "result", thus the intersection. And L1 and L2 are the two sets to build the intersection.
It is a bit too general, though - like many Prolog predicates - think of append([], non_list, non_list). Apart from lists, your definition admits also terms that are neither lists nor partial lists:
?- intersection(non_list1,[1,2|non_list2],[3,4|non_list3]).
To make it really useful safe, use it like so:
?- when(ground(intersection(I, A, B)), intersection(I, A, B)).
or so:
?- ( ground(intersection(I, A, B))
-> intersection(I, A, B)
; throw(error(instantiation_error, intersection(I, A, B)))
).
Or, using iwhen/2:
?- iwhen(ground(intersection(I, A, B)), intersection(I, A, B) ).
As a minor remark, rather write (\+)/1 in place of not/1.
The problem is that not/1 merely negates the outcome of your element/2. It doesn't cause element/2 to backtrack to find other instantiations for which the enclosing not/1 will be true.
Consider the following program.
a(1).
a(2).
b(1).
b(2).
b(3).
And the following queries:
b(X), not(a(X)).
not(a(X)), b(X).
The first one yields X = 3 while the second one yields false. That is because the first query first instantiates X with 1, then with 2, then with 3, until finally not(a(X)) succeeds.
The second query first instantiates X with 1, a(1) succeeds, so not(a(1)) fails. There is no backtracking done!
The lack of backtracking due to negation as pointed out by #SQB is actually not the only problem with your code. If you play around a little with ground queries you find that non-lists and the empty list as pointed out by #false are also not the only issue. Consider the following queries:
?- intersection([2,3],[1,2,3],[2,3,4]).
yes
?- intersection([2],[1,2,3],[2,3,4]).
yes
?- intersection([3],[1,2,3],[2,3,4]).
yes
?- intersection([],[1,2,3],[2,3,4]).
yes
The first is what usually is understood as intersection. The other three are all sublists of the intersection including the trivial sublist []. This is due to the way the predicate describes what an intersection is: In an intersection is not the case that an element is in the first but not the second list AND that said element is in the first but not the third list. This description clearly fits the three above queries hence they succeed. Fooling around a little more with this description in mind there are some other noteworthy ground queries that succeed:
?- intersection([2,2,3],[1,2,3],[2,3,4]).
yes
The question whether the presence of duplicates in the solution is acceptable or not is in fact quite a matter of debate. The lists [2,2,3] and [2,3] although different represent the same set {2,3}. There is this recent answer to a question on Prolog union that is elaborating on such aspects of answers. And of course the sublists of the intersection mentioned above can also contain duplicates or multiples:
?- intersection([2,2,2],[1,2,3],[2,3,4]).
yes
But why is this? For the empty list this is quite easy to see. The query
?- element(A,[]).
no
fails hence the conjunction element(A,L1), not(element(A,L2)) also fails for L1=[]. Therefore the negation wrapped around it succeeds. The same is true for the second negation, consequently [] can be derived as intersection. To see why [2] and [3] succeed as intersection it is helpful to write your predicate as logic formula with the universal quantifiers written down explicitly:
∀L1∀L2∀R∀A (intersection(L1,L2,R) ← ¬ (element(A,L1) ∧ ¬ element(A,L2)) ∧ ¬ (element(A,L1) ∧ ¬ element(A,R)))
If you consult a textbook on logic or one on logic programming that also shows Prolog code as logic formulas you'll find that the universal quantifiers for variables that do not occur in the head of the rule can be moved into the body as existential quantifiers. In this case for A:
∀L1∀L2∀R (intersection(L1,L2,R) ← ∃A ( ¬ (element(A,L1) ∧ ¬ element(A,L2)) ∧ ¬ (element(A,L1) ∧ ¬ element(A,R))))
So for all arguments L1,L2,R there is some A that satisfies the goals. Which explains the derivation of the sublists of the intersection and the multiple occurrences of elements.
However, it is much more annoying that the query
?- intersection(L1,[1,2,3],[2,3,4]).
loops instead of producing solutions. If you consider that L1 is not instantiated and look at the results for the following query
?- element(A,L1).
L1 = [A|_A] ? ;
L1 = [_A,A|_B] ? ;
L1 = [_A,_B,A|_C] ? ;
...
it becomes clear that the query
?- element(A,L1),not(element(A,[1,2,3])).
has to loop due to the infinitely many lists L1, that contain A, described by the first goal. Hence the corresponding conjunction in your predicate has to loop as well. Additionally to producing results it would also be nice if such a predicate mirrored the relational nature of Prolog and worked the other way around too (2nd or 3rd arguments variable). Let's compare your code with such a solution. (For the sake of comparison the following predicate describes sublists of the intersection just as your code does, for a different definition see further below.)
To reflect its declarative nature lets call it list_list_intersection/3:
list_list_intersection(_,_,[]).
list_list_intersection(L1,L2,[A|As]) :-
list_element_removed(L1,A,L1noA),
list_element_removed(L2,A,L2noA),
list_list_intersection(L1noA,L2noA,As).
list_element_removed([X|Xs],X,Xs).
list_element_removed([X|Xs],Y,[X|Ys]) :-
dif(X,Y),
list_element_removed(Xs,Y,Ys).
Like your predicate this version is also using the elements of the intersection to describe the relation. Hence it's producing the same sublists (including []):
?- list_list_intersection([1,2,3],[2,3,4],I).
I = [] ? ;
I = [2] ? ;
I = [2,3] ? ;
I = [3] ? ;
I = [3,2] ? ;
no
but without looping. However, multiple occurrences are not produced anymore as already matched elements are removed by list_element_removed/3. But multiple occurrences in both of the first lists are matched correctly:
?- list_list_intersection([1,2,2,3],[2,2,3,4],[2,2,3]).
yes
This predicate also works in the other directions:
?- list_list_intersection([1,2,3],L,[2,3]).
L = [2,3|_A] ? ;
L = [2,_A,3|_B],
dif(_A,3) ? ;
L = [2,_A,_B,3|_C],
dif(_A,3),
dif(_B,3) ? ;
...
?- list_list_intersection(L,[2,3,4],[2,3]).
L = [2,3|_A] ? ;
L = [2,_A,3|_B],
dif(_A,3) ? ;
L = [2,_A,_B,3|_C],
dif(_A,3),
dif(_B,3) ? ;
...
So this version corresponds to your code without the duplicates. Note how the element A of the intersection explicitly appears in the head of the rule where all elements of the intersection are walked through recursively. Which I believe is what you tried to achieve by utilizing the implicit universal quantifiers in front of Prolog rules.
To come back to a point in the beginning of my answer, this is not what is commonly understood as the intersection. Among all the results list_list_intersection/3 describes for the arguments [1,2,3] and [2,3,4] only [2,3] is the intersection. Here another issue with your code comes to light: If you use the elements of the intersection to describe the relation, how do you make sure you cover all intersecting elements? After all, all elements of [2] occur in [1,2,3] and [2,3,4]. An obvious idea would be to walk through the elements of one of the other lists and describe those occurring in both as also being in the intersection. Here is a variant using if_/3 and memberd_t/3:
list_list_intersection([],_L2,[]).
list_list_intersection([X|Xs],L2,I) :-
if_(memberd_t(X,L2),
(I=[X|Is],list_element_removed(L2,X,L2noX)),
(I=Is,L2noX=L2)),
list_list_intersection(Xs,L2noX,Is).
Note that it is also possible to walk through the arguments of the second list instead of the first one. The predicate memberd_t/3 is a reified variant of your predicate element/2 and list_element_removed/3 is again used in the description to avoid duplicates in the solution. Now the solution is unique
?- list_list_intersection([1,2,3],[2,3,4],L).
L = [2,3] ? ;
no
and the "problem queries" from above fail as expected:
?- list_list_intersection([1,2,3],[2,3,4],[]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2]).
no
?- list_list_intersection([1,2,3],[2,3,4],[3]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2,2,3]).
no
?- list_list_intersection([1,2,3],[2,3,4],[2,2,2]).
no
And of course you can also use the predicate in the other directions:
?- list_list_intersection([1,2,3],L,[2,3]).
L = [2,3] ? ;
L = [3,2] ? ;
L = [2,3,_A],
dif(_A,1) ? ;
...
?- list_list_intersection(L,[2,3,4],[2,3]).
L = [2,3] ? ;
L = [2,3,_A],
dif(4,_A) ? ;
...

Prolog notBetween function

I need some help here with Prolog.
So I have this function between that evaluates if an element is between other two.
What I need now is a function that evaluates if a member is not between other two, even if it is the same as one of them.
I tried it :
notBetween(X,Y,Z,List):-right(X,Y,List),right(Z,Y,List). // right means Z is right to Y and left the same for the left
notBetween(X,Y,Z,List):-left(X,Y,List),left(Z,Y,List).
notBetween(X,Y,Z,List):-Y is Z;Y is X.
I am starting with Prolog so maybe it is not even close to work, so I would appreciate some help!
When it come to negation, Prolog behaviour must be handled more carefully, because negation is 'embedded' in the proof engine (see SLD resolution to know a little more about abstract Prolog). In your case, you are listing 3 alternatives, then if one will not be true, Prolog will try the next. It's the opposite of what you need.
There is an operator (\+)/2, read not. The name has been chosen 'on purpose' different than not, to remember us that it's a bit different from the not we use so easily during speaking.
But in this case it will do the trick:
notBeetwen(X,Y,Z,List) :- \+ between(X,Y,Z,List).
Of course, to a Prolog programmer, will be clearer the direct use of \+, instead of a predicate that 'hides' it - and requires inspection.
A possibile definition of between/4 with basic lists builtins
between(X,Y,Z,List) :- append(_, [X,Y,Z|_], List) ; append(_, [Z,Y,X|_], List).
EDIT: a simpler, constructive definition (minimal?) could be:
notBetween(X,Y,Z, List) :-
nth1(A, List, X),
nth1(B, List, Y),
nth1(C, List, Z),
( B < A, B < C ; B > A, B > C ), !.
EDIT: (==)/2 works with lists, without side effects (it doesn't instance variables). Example
1 ?- [1,2,3] == [1,2,3].
true.
2 ?- [1,2,X] == [1,2,X].
true.
3 ?- [1,2,Y] == [1,2,X].
false.

Prolog - how to understand lists

I don't know much, how to understand that fact p([H|T], H, T). I know C/C++/Java etc.. but this looks diferrent. So when i pass first argument to "function" p, it separates it into H and T and makes it accessible through this vars? I don't know how to logically understand this.
http://www.doc.gold.ac.uk/~mas02gw/prolog_tutorial/prologpages/lists.html
p([H|T], H, T).
Lets see what happens when we ask some simple queries.
?- p([a,b,c], X, Y).
X=a
Y=[b,c]
yes
In Prolog we have relations, in a way similar to relationals DBs.
Then p/3 it's a relation among a list (first argument), its head H and its tail T.
Appropriately the tutorial' author used descriptive and synthetic symbols as Variables.
Syntactically, variables are symbols starting Uppercase and can get any value, but only one time (that is, cannot be 'reassigned').
The page you refer to says, "Consider the following fact.
p([H|T], H, T)."
So we must treat this as a fact. That means, it's like having a predicate
p([H|T], H, T):- true. % or, p(L,H,T) :- L=[H|T].
Now, when you query p([a,b,c], X, Y)., one is put besides the other:
p([a,b,c], X, Y). % a query
p([H|T], H, T) :- true. % a rule's clause: _head_ :- _body_.
the equivalences are noted: [a,b,c] = [H|T], X = H, Y = T and treated as unification equations. The first gets further translated into
a = H % list's head element
[b,c] = T % list's tail
because [A|B] stands for a list with A the head element of the list, and B the list's tail, i.e. all the rest of its elements, besides the head. H and T are common mnemonic names for these logical variables.
So on the whole, we get X = H = a, Y = T = [b,c].
This process is what's known as unification of a query and a rule's head (the two things starting with a p "functor", and both having the 3 "arguments").
Since the query and the head of a rule's "clause" matched (had same functor and same number of arguments), and their arguments were all successfully unified, pairwise, using the above substitution, we only need to prove the body of that rule's clause (that was thus selected).
Since it is true, we immediately succeed, with the successful substitution as our result.
That's how Prolog works.
TL;DR: yes, when you call p(L,H,T) with a given list L, it will be destructured into its head H and tail T. But you may call it with a given list T, a value H, and a variable L, and then a new list will be constructed from the head and the tail. And if L is given as well, it will be checked whether its head is H, and its tail is T.
This is because Prolog's unification is bi-directional: A = B is the same as B = A. Unification with a variable is like setting that variable, and unification with a value is like checking the (structural) equality with that value.
Calling p(L,H,T) is really equivalent to the unification L = [H|T].

Resources