Two different ways to express List in Prolog - prolog

what's the difference between these two clauses:
L=[X,H|Y].
append(X,[H|Y],L).
It's one clause in my code, first one does not work, second one works, just don't know the difference.

The expression [X,H|Y] denotes a list whose first term is the value of X, whose second term is the value of H, and whose tail is the value of Y. If X = 1, H = 2, and Y = [3,4,5], its value will be [1,2,3,4,5]. If X = [1,2,3], H = [4,5,6], and Y = [7,8,9], its value will be [[1,2,3], [4,5,6], 7, 8, 9]. The expression L=[X,H|Y] binds the value of the list to L.
The predicate append(X,[H|Y],L), on the other hand, appends the list whose first term is H and whose tail is Y to the list X, and binds the result to L. If X = 1, H = 2, and Y = [3,4,5], the result will be an error, since X is not a list. If X = [1,2,3], H = [4,5,6], and Y = [7,8,9], the result will be to bind L to the value [1,2,3, [4,5,6], 7, 8, 9].

Related

Finding consecutive sublists of a list

I want to write a predicate split/2 that generates all consecutive lists found inside another list.
Example: split([1,2,3,4],X) should return
X = [4], X = [2,3],X = [1,2], X = [1,2,3] etc.
So far I only have a predicate that returns all possible sublists of a list:
sublist([],[]).
sublist([H|T], [H|R]) :-
sublist(T,R).
sublist([_|T], R) :-
sublist(T,R).
However, with the query from the example this predicate includes unwanted answers like X = [2,4] and X = [1,3] that aren't found consecutively in [1,2,3,4].
Usually a problem is easier if you split it in subproblems. We can first construct a predicate that will construct all suffixes for a given list.
We can construct such predicate as follows:
suffix(_, []).
suffix([H|T], [H|T2]) :-
suffix(T, T2).
So for each point in the list, we can decide to stop (with the empty list), or emit the next item. For the given sample list, we thus get:
?- suffix([1,2,3,4],X).
X = [] ;
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [1, 2, 3, 4].
Now we only need to decide when we start the suffix. For each item in the list, we can decide to start at that point, and enumerate over all suffixes that we then append to that item:
split([H|T], [H|S]) :-
suffix(T, S).
split([_|T], S) :-
split(T, S).
For example:
?- split([1,2,3,4],X).
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [1, 2, 3, 4] ;
X = [2] ;
X = [2, 3] ;
X = [2, 3, 4] ;
X = [3] ;
X = [3, 4] ;
X = [4] ;
false.
The nice thing is that we got a second predicate "for free": we can also obtain all suffixes for a list.
We might want to include the empty list as well. I leave this as an exercise.

How can I replace a list in Prolog?

I think it's very easy but I have no idea how to do that.
I tried by attribuition, doing a list receive another list but don't work.
% H is the head of a coordenate and T the tail
% E is the element that will be placed in the position T
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],H,T,E,NewTray) :-
H is 1,replace(L1,T,E,N),L1 = N;
H is 2,replace(L2,T,E,N),L2 = N;
...
H is 10,replace(L10,T,E,N),L10 = N;
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
I need that L1 be the N in this clause, I don't know how I can create a clause to modify the L1 inside the clause findLine. I thought in create clause to remove all elements and add the new ones one by one and call this at the attribuition place:
%L is the list, C a counter and N the new list
rewrite(L,C,N) :-
Q is C,
removeByIndex(Q,L,R),
(Q \== 0 -> rewrite(R,Q-1,N), !.
removeByIndex(0,[_|T],T):- !.
removeByIndex(I,[H|T],R):- X is I - 1, removeByIndex(X, T, Y), insert(H, Y, R).
But I continous with the same problem: the L1 are not modified :(
The idea is modify a line and replace on the tray.
PS: I'm sorry for my english, but the prolog topics are almost inative in the portuguese forum
I'm really unsure what you're trying to accomplish here, but I can point to a few things that strike me as symptoms of a misunderstanding.
First of all, you bind all the variables at the top and then you have essentially a bottom-out else case that looks like this:
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
Well, you never assign to NewTray in any of your other cases, so NewTray is going to be uninstantiated most of the time. That does not seem likely to be what you intend to me.
Second, your cases have this structure:
H is 1,replace(L1,T,E,N),L1 = N;
First mistake here is that H is 1; is/2 is for evaluating arithmetic expressions; there's no difference between this and H = 1, and the equivalence of L1 and N means that this whole predicate could probably be written as:
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],1,T,E,_) :-
replace(L1,T,E,L1).
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],2,T,E,_) :-
replace(L2,T,E,L2).
findLine(Line, _, _, Line).
I'm still confused by what you're trying to do, looking at that.
I suspect that you think L1 will have some value on the way into the relation and suddenly have a new, different value after the relation is used. That is emphatically not the case: variables in Prolog are bound exactly once; your assignment L1 = N or whatever is not going to cause L1 to "receive a new value" (because such a thing cannot happen in Prolog); instead it informs Prolog that L1 and N should be bound to the same value. What this means depends on circumstances; if they are both ground and not equal it will cause your predicate to fail, for instance, but if either of them is non-ground they will accept the value of the other.
I'm looking at what you're doing here and I can't help but think that you're essentially trying to do this:
replace([], _, _, []).
replace([H|T], 1, X, [X|T]).
replace([H|T], N, X, [H|Replaced]) :-
N > 1, succ(N0, N), replace(T, N0, X, Replaced).
Use it like this:
?- replace([1,2,3,4,5], 3, foo, Result).
Result = [1, 2, foo, 4, 5]
I just can't for the life of me figure out what you're trying to do, and I don't know why you're bothering to bind all the variables in your list at once if you don't need them all at once.
Anyway, I hope this helps! Maybe if you show us more of what you're trying to do it will be more clear how we can help.
Edit: Elaboration on = and unification
Let's mess around with = and see what happens:
?- X = 3.
X = 3.
Probably nothing surprising about this.
?- 3 = X.
X = 3.
Unification is different from assignment. As you can see, it is not directional. This line would not have worked in any other language.
?- X = [1,Y,3].
X = [1, Y, 3].
Notice that Prolog has no issues with having variables remain free.
?- X = [1,Y,3], Y = 2.
X = [1, 2, 3],
Y = 2.
Now, because Y is the same in both positions, when you bound Y to 2, the middle value in X became 2 as well. There are data structures unique to Prolog that make use of this feature (difference lists).
?- X = [1,Y,3], Q = X, Q = [1,2,3].
X = Q, Q = [1, 2, 3],
Y = 2.
Now what makes this interesting is that we did not explicitly tell Prolog that Y is 2. Prolog inferred this by unification. You can see some more examples of that here:
?- X = [H|T], H = 3, T = [4,5].
X = [3, 4, 5],
H = 3,
T = [4, 5].
So here we said, X is composed of H and T and then told it what H and T are. But Prolog's unification doesn't care much about the order you do things:
?- X = [H|T], X = [1,2,3].
X = [1, 2, 3],
H = 1,
T = [2, 3].
Unification is transitive.
So what happens when Prolog cannot unify?
?- X = [1,Y,3], Q = X, Q = [1,2,3], Y = 4.
false.
Y has to be 2 for the first step, but it has to be 4 for the last step. Once a variable is bound, there's no changing it. This is just a more complex way of saying:
?- X = 2, X = 4.
false.
Prolog does not have "assignables", just variables.

How to generate every [X,Y] possible for a given list?

I'm trying to generate every combination possible given a list. I want every [X,Y] combination possible.
Here's an example :
?- arguments(A,[1,2,3]).
A = [1,2] ; A = [1,3] ; A = [2,1] ; A = [2,3] ; A = [3,1] ;
A = [3,2]
I have tried multiple things, but I've yet to find a working one.
I am pretty sure the idea is to use prolog's ability to try every possibility as such :
element(X,[X|_],1).
element(X,[_|Q],N) :- element(X,Q,NewN), N is NewN + 1.
This predicate can return the element at the position N, or return the position of the element X, or generate every possibility. Exemple :
?- element(X,[a,b,c],N).
N = 1
X = a
N = 2
X = b
N = 3
X = c
Thanks for the help.
Edit following gusbro answer :
I can't use already existing predicates, it's part of a course.
Reading your answer, I came up with this :
remove_element_x(X, [X|Q], Q).
remove_element_x(X, [T|Q], [T|Res]) :- remove_element_x(X,Q,Res).
arguments([X,Y],L) :-
element(X,L,_),
remove_element_x(X,L,L2),
element(Y,L2,_).
remove_element_x/3 remove the element x from the list and returns the new list.
But the backtracking is not working :
?- arguments(A,[1,2,3]).
A = [1,2] ?
yes
You can use select/3 to select an element from a list (and get the remaining list), then do it again to select another element from the remaining list).
i.e.:
arguments([A,B], L):-
select(A, L, L1),
select(B, L1,_).
Test case:
?- arguments(A,[1,2,3]).
A = [1, 2] ;
A = [1, 3] ;
A = [2, 1] ;
A = [2, 3] ;
A = [3, 1] ;
A = [3, 2]

Prolog - descending order list

I am trying to write a function - decListRange(X,List) which give a list in range [X-1:1] by descending order. For example -
decListRange(9,List).
Will give -
List = [8,7,6,5,4,3,2,1].
I tried the following but it goes into infinite loop -
decListRange(1,[]) :- !.
decListRange(X,[H|Rest]) :-
H = X-1, NextX = X - 1 ,decListRange(NextX,Rest).
You have two problems. The first real one is that you need to use is instead of =:
H is X-1
This is needed to trigger arithmetic evaluation. Your second problem isn't a real problem but speaks to a bigger misunderstanding, which is that H and NextX are equivalent. Because Prolog only has bindings and not "assignables" as it were, you should never really need to create two "variables" with the same binding. There's no state being kept around for you to modify later.
Cleaning up both you get this:
decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
X > 1,
H is X-1,
decListRange(H, Rest).
Edit 2: a clpfd implementation
:- use_module(library(clpfd)).
declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []).
declist(N, [N1|Ns]) :-
N #> 1,
N1 #= N - 1,
declist(N1, Ns).
This one has the properties #false mentions below in the comments:
?- declist(3, L).
L = [2, 1] ;
false.
?- declist(3, [2,1]).
true ;
false.
?- declist(N, [3,2,1]).
N = 4.
?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
Edit: a short interlude on the difference between = and is.
In procedural languages = is almost always syntax for assigning a particular value to a variable. In Prolog, variables are bindings, and once established they cannot be directly modified by reassigning the variable a different value. Instead they work more like variables in math and logic, where the variable "stands in" for interesting values, but those values are themselves basically immutable. In Prolog, = essentially asks the unification engine to establish bindings. So if you were to do something like this:
?- name(X, Y) = name(bob, tony).
Prolog responds with variable bindings:
X = bob,
Y = tony.
Once those bindings exist, contradictory bindings will fail and affirmative bindings will succeed:
?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.
?- name(X, Y) = name(bob, tony), X = william.
false.
The unification algorithm itself doesn't know anything about arithmetic. This has the pleasant side-effect that you can use any expression raw. For instance:
?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
This is probably really surprising looking. You may expect that somehow Prolog was smart enough to keep the expression around because it noticed X was a variable or something, but that isn't true either:
?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
Another way of looking at this is that Prolog is considering + to be just another operator, so X+3 is a fact just like add(X, 3) that doesn't necessarily have any special meaning. Whichever way you look at it, the is/2 operator exists to apply arithmetic reasoning and produce a value:
?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
Notice that Expr has the computed value but none of the original structure:
?- X = 4, Expr is X + 3, Z + Q = Expr.
false.
In practice, if you need to do a lot of reasoning with arithmetic, you will want to use a library like clpfd or clpqr depending on whether you're interested in integers or reals. This library enables you to do more interesting things more easily, like specify that an equation holds for values in a certain range and get those values out.

How do I find all solutions to a goal in Prolog?

I have predicate P1 that returns values one after the other like this:
-? P1(ARGUMENTS, RETURN).
-? RETURN = 1;
-? RETURN = 2;
-? RETURN = 3;
-? fail.
I also have another predicate called P2:
P2(ARGUMENTS, LIST) :- P1(ARGUMENTS, RETURN),... % SOMEHOW HERE I NEED TO INSERT ALL VALUES OF RETURN TO LIST.
How do find all of the values of RETURN and assign them to LIST?
Use findall to accomplish this:
P2(ARGUMENTS, LIST) :- findall(X, P1(ARGUMENTS, X), LIST).
This is related to the bagof function mentioned in the question linked to by Anders Lindahl. There is a good explanation on the relationship between the two functions (and a third function setof) here:
To illustrate the differences consider
a little example:
listing(p).
p(1,3,5).
p(2,4,1).
p(3,5,2).
p(4,3,1).
p(5,2,4).
Try the following goals. (The answer
displays have been modified to save
space.)
?- bagof(Z,p(X,Y,Z),Bag).
Z = _G182 X = 1 Y = 3 Bag = [5] ;
Z = _G182 X = 2 Y = 4 Bag = [1] ;
Z = _G182 X = 3 Y = 5 Bag = [2] ;
Z = _G182 X = 4 Y = 3 Bag = [1] ;
Z = _G182 X = 5 Y = 2 Bag = [4] ;
No
?- findall(Z,p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [5, 1, 2, 1, 4] ;
No
?- bagof(Z,X^Y^p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [5, 1, 2, 1, 4] ;
No
?- setof(Z,X^Y^p(X,Y,Z),Bag).
Z = _G182 X = _G180 Y = _G181 Bag = [1, 2, 4, 5] ;
No
The predicates bagof and setof yield
collections for individual bindings of
the free variables in the goal. setof
yields a sorted version of the
collection without duplicates. To
avoid binding variables, use an
existential quantifier expression. For
example the goal
bagof(Z,X^Y^p(X,Y,Z),Bag) asks for
"the Bag of Z's such that there exists
an X and there exists a Y such that
p(X,Y,Z)". findall acts like bagof
with all free variables automatically
existentially quantified. In addition
findall returns an empty list [] there
is no goal satisfaction, whereas bagof
fails.

Resources