Why it doesn't unify? prolog - prolog

Here we have two predicates
len -> return the length of a list.
processRel -> calls len.
len([],0).
len([_|T], R):-
len(T,X),
R is X+1.
processRel([H|Q],X):-
len(H,X).
why it doesn't unify?
it returns this:
?- processRel([1,2,3,4],X).
false.
Instead of (my expectation):
X = 4.
The predicates "len" works, I've already tested it, but I don't understand why if put that predicates in another, it works like that. thank you!

You should make it
processRel(L,X):-
len(L,X).
Right now, it is
processRel([H|Q],X):-
len(H,X).
Inserting [1,2,3,4] means we get
processRel([1,2,3,4],X):-
len(1,X).
So it unifies to len(1,X). Which isn't defined because 1 is not a list.

Related

Prolog : return variable, check if variable is of certain type?

I am new to Prolog and can't understand predicates very well.
First question: How can I 'return' a certain variable?
We have alternate(?A, ?B). alternate(first, second) should give me back second, and alternate(second, first) should give back first.
Second question: How to check if variable is of certain type?
I have for example ispair(?Pair). I have to check if Pair is pos(X,Y).
Not sure if that's what you meant, but what about the following:
alternate(first, pair(X,_), X).
alternate(second, pair(_,X), X).
If you query without any restrictions, you get the following two answer substitutions:
?- alternate(X,Y,Z).
X = first,
Y = pair(Z, _5844) ; % hit ; to get the second answer
X = second,
Y = pair(_5842, Z). % variables _12345 are fresh ones created by prolog
You can also ask: on which side of the pair (a,b) is b?
?- alternate(Where, pair(a,b), b).
Where = second.
In the case that your pair is (b,b), you get two solutions:
?- alternate(Where, pair(b,b), b).
Where = first ;
Where = second.
Also, c is not part of the pair (a,b):
?- alternate(Where, pair(a,b), c).
false.
If you insist on picking an element from heaven, you will get no as answer:
?- alternate(heaven, X, Y).
false.
When you know that the first element of a pair is a, prolog will tell you how the pair must look like:
?- alternate(first, X, a).
X = pair(a, _5680).
Again we have a fresh variable (_5680) in there, because any second term is fine.

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]]

Prolog assigning values to elements of a list

I am new to Prolog and the problem I am dealing with is the following: Given a list of variables, I want to assign a value for each element of that list, and then check if a restriction containing some of those variables is true. This is an example of how I thought it should work:
predicate(L1, Restriction) :-
foreach(member(Var,L1), Var = 1),
Restriction.
But when I write in the console:
? - predicate([A,B,C], A==1).
or
? - predicate([A,B,C], B==1).
or
? - predicate([A,B,C], A==B).
they all return false.
Shouldn't A, B, and C be all equivalent to 1 after the foreach loop?
Paulo explained well what the problem is (+1). Maybe you should correct your code like
predicate(L1, Restriction) :-
maplist(=(1), L1),
Restriction.
that yields the expected output
?- predicate([A,B,C], A==1).
A = B, B = C, C = 1.
The problem is the way the foreach/2 predicate works. The first argument works as a generator and the second argument works as a test for each solution of the generator. But the predicate creates a conjunction where each element is a copy of the second argument. Because of this copying, the variables in the generator never get instantiated (as you're instantiating the copies). This semantics can be illustrated by the following query:
?- foreach(member(Var, [A,B,C]), Var = 1), var(A), var(B), var(C).
true.
As your restriction is the predicate/2 calls is an equality test and a variable is not equal to an integer, all the calls fail.
If your intention is to create a list of a given length with all elements equal to a given term, there are several ways of accomplishing it. For example, using only standard built-in predicates:
?- findall(1, between(1, 3, _), List).
List = [1, 1, 1].

Appending lists in Prolog with functor

I am trying to use Prolog's append and length predicates for the first time in order to split a list, and I believe it requires a recursive solution. I am new to Prolog, and would like some help with this starter problem! :)
Here is the expected code output:
?- splits([1,2,3],S).
S = [1]/[2, 3] ;
S = [1, 2]/[3] ;
false.
It takes a list and splits it, but it does so by creating a structure with the functor /, this is what confuses me so far... I know that I need to use append for this, but how would one do so?
Here is my code so far:
splits([H | T], S) :-
length(T, len), len > 0,
It will run until the tail of the list is empty, and then stop, but I can't quite figure out how to add in the append function or make it recursive... Could someone give me a tip? :)
I would say that you are almost at a working implementation with your remark that append/3 can be used for splitting lists. This is indeed what append/3 in the instantiation (-,-,+) does.
The only added requirement that seems to occur in your question is to exclude cases in which either of the splits is empty. This can be achieved by checking for inequivalence between terms using \==/2.
This results in the following code:
splits(List, X/Y):-
append(X, Y, List),
X \== [],
Y \== [].
PS: Notice that your use of len in your code snippet is wrong, since len is not a Prolog variable but an atom. Handing an atom to the second argument of length/2 produces a type error, and an arithmetic error in len > 0 (provided that len is not defined as a function). (Both observations relate to SWI-Prolog.)
Hope this helps!
Here is a recursive approach:
splits([A,B|T], [A]/[B|T]).
splits([A|T], [A|R]/S) :-
splits(T, R/S).
The first clause provides the base case of splitting a list with at least 2 elements ([A,B|T]) into [A]/[B|T] (it just splits out the first element).
The second clause says that [A|R]/S is the split of [A|T] if R/S is the split of T. So it will "generate" the other solutions recursing down to the base case. If the first list has only two elements, the base case will be successful, and backtrack to the recursive case will fail on the first try (which is what you want - no more solutions to that case) because the recursive case only succeeds when the first list has 3 or more elements (A plus the two enforced on T in the recursive query).
| ?- splits([1], S).
no
| ?- splits([1,2], S).
S = [1]/[2] ? ;
no
| ?- splits([1,2,3], S).
S = [1]/[2,3] ? ;
S = [1,2]/[3] ? ;
no
...

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.

Resources