What is the exact meaning of the equal sign in Elixir? - functional-programming

I don't get what exactly means the equal sign in Elixir.
What is unclear is that it looks like a mix between assignment and a pattern matching operation.
iex(1)> x=4
4
iex(2)> y=5
5
iex(3)> 3=y
** (MatchError) no match of right hand side value: 5
iex(3)> y=3
3
iex(4)> y=x
4
I understand that in Elixir, the equals operator means to match the left side of the = sign to the the right side. First two lines make sense to me. x and y are unbound variables, hence they could match anything. They are bound as they match. Consequently, I understand the third line. You can't match 3 with 5.
Where I start to loose my head is why the hell the two last lines are executed without giving the same error. It looks like the equal sign is back to being an assignment operator only.
I've try to accept this behaviour as a fact without full understanding and tried to go further in the learning of the language. But as pattern matching is one of the core mechanism of Elixir, I'm constantly lock and feel I should go back to this original question. I will not go any further before I fully understand what exactly happens with the "=" sign and what is the logic.

The equals sign means: "try to fit the value of expression on the right to the shape on the left and assigning values accordingly". So left and right side are different and you cannot switch them. On the right side all variables have to be bound, because it is an expression. On the left side even if you use variables that are already bound they will be reassigned.
So first thing is that on the right you can have any expression your want:
{:error, :enoent} = File.open("foo")
but you can't have an expression on the left side:
iex(1)> File.open("foo") = {:error, :enoent}
** (CompileError) iex:1: cannot invoke remote function File.open/1 inside match
In case of
y=3
5=y # y gets evaluated to 3 and then you pattern match 3=5
and it fails. But you can do
y=3
y=5 # y gets reassigned.
On the left hand side you can only have "shape" which may be arbitrarly nested datastructure:
[a, b, %{"a" => {1, c}}] = [1, 2, %{"a" => {1, 2}]
# c is now assigned value of 2
So pattern matching is used to either destructure data or to assert some condition like
case File.open("foo") do
{:ok, contents} -> enjoy_the_file(contents)
{:error, reason} -> print_error(reason)
end
or if you want to assert that there is only one entity in the database instead of firstly asserting it exists and then that there is only one you can pattern match:
[entity] = Repo.all(query)
If you want to assert that the first value in a list is one, you can pattern match:
[1 | rest] = [1, 2, 3]
There are some gotchas when pattern matching. For example this:
%{} = %{a: "a"}
will match, because shape on the left side is a map and you don't require anything more so any map will match. However this won't match:
%{a: "a"} = %{}
because shape on the left says "give me a map with a key of atom :a.
If you would like to match on a variable you may write something like this:
a = 1
{a, b} = {2, 3}
but this will assign a the value 2. Instead you need to use pin operator:
a = 1
{^a, b} = {2, 3} #match fails
I wrote more about pin operator in this answer: What is the "pin" operator for, and are Elixir variables mutable?

Where I start to loose my head is why the hell the two last lines are executed without giving the same error. It looks like the equal sign is back to being an assignment operator only.
That's because a variable name on the left side is not matched by its value in Elixir. Instead, the variable is reassigned to the matching value on the right side.
This is different from Erlang where exactly what you expect happens:
1> X = 4.
4
2> Y = 5.
5
3> 3 = Y.
** exception error: no match of right hand side value 5
4> Y = 3.
** exception error: no match of right hand side value 3
5> Y = X.
** exception error: no match of right hand side value 4
To get the same behavior in Elixir, you need to use the "pin" operator on each variable you want to match by value on the left side:
iex(1)> x = 4
4
iex(2)> y = 5
5
iex(3)> 3 = y
** (MatchError) no match of right hand side value: 5
iex(3)> ^y = 3
** (MatchError) no match of right hand side value: 3
iex(3)> ^y = x
** (MatchError) no match of right hand side value: 4

Two cases:
1) Left hand side is placeholder/variable:
Whatever in right will get assigned
Example:
x = 5
y = x (y gets value 5)
x = y (x gets value 5)
2) Left hand side is value
Match with the right hand value/variable's value
Example:
5 = x (Error: as x is undefined)
x = 5
5 = x (5 matches with 5)
6 = x (Error: 6 is not matches with 5)

Related

How to return in prolog all elements from right to left greater than an integer in one predicate?

I have to write a code that return all elements from a given list which are strictly greater than a given integer, it returns from left to right. I cannot use recursion or any other function except the built-in functions: append/3, append/2, member/2, select/3, reverse/2, findall/3, bagof/3, setof/3, sumlist/2
Example case:
greater_list([1,9,2,8,3,7,12],7, X).
X = 12 ? ;
X = 8 ? ;
X = 9 ? ;
no
I can write it with recursion or help predicates, but without them I do not know how to start. I could use findall/3 but it would not return element by elements, but a list of elements greater than that given number.
I can write it with recursion or help predicates, but without them I do not know how to start.
I would be interested in how you think you can solve this with helper predicates but not without.
But for starting, consider this: What you need to do is to enumerate certain elements of the list. That is, enumerate elements of the list that have some property.
So to start, you need to know how to enumerate elements of the list. Once you know how to do that, you can worry about the property that they must fulfill.
You can enumerate list elements using member/2:
?- member(X, [1,9,2,8,3,7,12]).
X = 1 ;
X = 9 ;
X = 2 ;
X = 8 ;
X = 3 ;
X = 7 ;
X = 12.
Now, we want to enumerate elements, but only those that fulfill the property X > 7. This is equivalent to saying that "X is a member of the list, and X > 7". In Prolog, (something like) "and" is written with a comma (,):
?- member(X, [1,9,2,8,3,7,12]), X > 7.
X = 9 ;
X = 8 ;
X = 12.
Your predicate is supposed to take a variable limit, not hardcode the limit of 7. This will be similar to:
?- Limit = 7, member(X, [1,9,2,8,3,7,12]), X > Limit.
Limit = 7,
X = 9 ;
Limit = 7,
X = 8 ;
Limit = 7,
X = 12.
Packing this up in a predicate definition will get you started. It looks like the order in which the elements are enumerated here is the reverse of what is intended. Maybe one of your built-ins helps you with this...
(Also, if you know how to write this using findall, you can then use member to enumerate the elements of the findall'ed list. But you shouldn't get in the habit of using findall in general, and especially not if the required solution isn't even a list. Beginners and bad teachers tend to over-emphasize putting things in lists, because that is what you have to do in lesser programming languages. Free yourself from thinking in other languages, even if your teacher can't.)
You can use findall/3 to get a list of the sought elements and then use member/2 to enumerate the members of that list:
greater_list(L,Limit,X) :-
findall(E,(member(E,L),E>Limit),Es),
member(X,Es).
Then:
?- greater_list([1,9,2,8,3,7,12],7, X).
X = 9 ;
X = 8 ;
X = 12.
?- greater_list([],7, X).
false.
And in a roundabout way:
?- findall(X, greater_list([1,9,2,8,3,7,12],7, X), Xs).
Xs = [9, 8, 12].
NB. this relies on recursion, I didn't notice that you couldn't use it at first
Instead of reversing the list, you can write the predicate without other helper predicates and consider first the recursive case. This ensures the first element to be checked against N will be the last element of the list.
greater_list([_|L], N, X) :- greater_list(L,N,X).
greater_list([X|_], N, X) :- X > N.
The lack of a clause for the empty list means that the predicate fails for empty lists.
The first clause above declares that X is item from a list that is greater than N if it is such an item in the sublist L.
The second clause, tried on backtracking, declares that the predicate is also true if X is the front element of the list and it is greater than N.
Both clause make Prolog search first in the sublist, and only when backtracking, consider the values stored in the list. As backtracking unfolds from deeper recursion levels first, the rule will be applied in a way that checks the last element first, then second to last, etc.
[eclipse 2]: greater_list([1,9,2,8,3,7,12],7, X).
X = 12
Yes (0.00s cpu, solution 1, maybe more) ? ;
X = 8
Yes (0.00s cpu, solution 2, maybe more) ? ;
X = 9
Yes (0.00s cpu, solution 3, maybe more) ? ;
No (0.00s cpu)

Return values in Prolog

I'm supposed to write a predicate that does some math stuff. But I don't know how to pass numbers or return numbers.
Maybe you can give me an example?
Let's say a predicate divide/2 that takes two numbers a and b and returns a/b.
Yes, you pass numbers in in some arguments, and you get the result back in some other argument(s) (usually last). For example
divide( N, D, R) :-
R is N / D.
Trying:
112 ?- divide(100,5,X).
X = 20.
113 ?- divide(100,7,X).
X = 14.285714285714286.
Now, this predicate is divide/3, because it has three arguments: two for inputs and one for the output "information flow".
This is a simplified, restricted version of what a Prolog predicate can do. Which is, to not be that uni-directional.
I guess "return" is a vague term. Expression languages have expressions e-value-ated so a function's last expression's value becomes that function's "return" value; Prolog does not do that. But command-oriented languages return values by putting them into some special register. That's not much different conceptually from Prolog putting some value into some logvar.
Of course unification is more complex, and more versatile. But still, functions are relations too. Predicates "return" values by successfully unifying their arguments with them, or fail to do so, as shown in the other answer.
Prolog is all about unifying variables. Predicates don't return values, they just succeed or fail.
Typically when a predicate is expected to produce values based on some of the arguments then the left-most arguments are inputs and the right-most are the outputs. However, many predicates work with allowing any argument to be an input and any to be a output.
Here's an example for multiply showing how it is used to perform divide.
multiply(X,Y,Z) :- number(X),number(Y),Z is X * Y.
multiply(X,Y,Z) :- number(X),number(Z),X \= 0,Y is Z / X.
multiply(X,Y,Z) :- number(Y),number(Z),Y \= 0,X is Z / Y.
Now I can query it like this:
?- multiply(5,9,X).
X = 45 .
But I can easily do divide:
?- multiply(5,X,9).
X = 1.8 .
It even fails if I try to do a division by 0:
?- multiply(X,0,9).
false.
Here's another approach. So let's say you have a list [22,24,34,66] and you want to divide each answer by the number 2. First we have the base predicate where if the list is empty and the number is zero so cut. Cut means to come out of the program or just stop don't go to the further predicates. The next predicate checks each Head of the list and divides it by the number A, meaning (2). And then we simply print the Answer. In order for it to go through each element of the list we send back the Tail [24,34,66] to redo the steps. So for the next step 24 becomes the Head and the remaining digits [34,66] become the Tail.
divideList([],0,0):-!.
divideList([H|T],A,Answer):-
Answer is H//A,
writeln(Answer),
divideList(T,A,_).
?- divideList([22,24,34,66],2,L).
OUTPUT:
11
12
17
33
Another simpler approach:
divideList([],_,[]).
divideList([H|T],A,[H1|L]):-
H1 is H//A,!,
divideList(T,A,L).
?-divideList([22,4,56,38],2,Answer).
Answer = [11, 2, 28, 19]

How to check equality of two FStar.Set's

How can you check whether two sets are equal in FStar? The following expression is of type Type0 not Tot Prims.bool so I'm not sure how to use it to determine if the sets are equal (for example in a conditional). Is there a different function that should be used instead of Set.equal?
Set.equal (Set.as_set [1; 2; 3]) Set.empty
The sets defined in FStar.Set are using functions as representation.
Therefore, a set s of integers for instance, is nothing else than a function mapping integers to booleans.
For instance, the set {1, 2} is represented as the following function:
// {1, 2}
fun x -> if x = 1 then true
else (
if x = 2 then true
else false
)
You can add/remove value (that is, crafting a new lambda), or asks for a value being a member (that is, applying the function).
However, when it comes to comparing two sets of type T, you're out of luck : for s1 and s2 two sets, s1 = s2 means that for any value x : T, s1 x = s2 x. When the set of T's inhabitants is inifinite, this is not computable.
Solution The function representation is not suitable for you. You should have a representation whose comparaison is computable. FStar.OrdSet.fst defines sets as lists: you should use that one instead.
Note that this OrdSet module requires a total order on the values held in the set. (If you want have set of non-ordered values, I implemented that a while ago, but it's a bit hacky...)

Why is x = x +1 valid in Elixir?

Everything I've read about Elixir says that assignment should be thought of as pattern matching. If so then why does x = x + 1 work in Elixir? There is no value of x for which x = x + 1.
Everything I've read about Elixir says that assignment should be thought of as pattern matching.
In Elixir, = is called the pattern match operator, but it does not work the same way as the pattern match operator in Erlang. That's because in Elixir variables are not single assignment like they are in Erlang. Here's the way Erlang works:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> X = 15.
15
2> X = 100.
** exception error: no match of right hand side value 100
3> X.
15
4>
Therefore, in Erlang this fails:
4> X = X + 1.
** exception error: no match of right hand side value 16
Things are pretty simple with Erlang's single assignment: because X already has a value, the line X = X + 1 cannot be an attempt to assign a new value to X, so that line is an attempt to pattern match (15 = 15 + 1), which will always fail.
On the other hand, in Elixir variables are not single assignment:
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> x = 15
15
iex(2)> x = 100
100
iex(3)> x
100
iex(4)>
The fact that variables are not single assignment in Elixir means that Elixir needs to make a choice when you write:
x = 10
x = x + 1 #or even x = 15
Choice 1) Should the second line be interpreted as assignment to x?
Choice 2) Should the second line be interpreted as an attempt to pattern match (i.e. 10 = 11)?
Elixir goes with Choice 1. That means that actually performing a pattern match with the so called pattern match operator in Elixir is more difficult: you have to use the pin operator(^) in conjunction with the match operator(=):
x = 10
^x = x + 1
Now, the second line will always fail. There is also a trick that will work in some situations if you want to perform pattern matching without using the pin operator:
x = 10
12 = x
In the second line, you put the variable on the right hand side. I think the rule can be stated like this: On the right hand side of the pattern match operator(=), variables are always evaluated, i.e. replaced with their values. On the left hand side variables are always assigned to--unless the pin operator is used, in which case a pinned variable is replaced by its current value and then pattern matched against the right hand side. As a result, it's probably more accurate to call Elixir's = operator a hybrid assignment/pattern match operator.
You can imagine x = x + 1 being rewritten by the compiler to something like x2 = x1 + 1.
This is pretty close to how it works. It's not a simple index number like I used here, but the concept is the same. The variables seen by the BEAM are immutable, and there is no rebinding going on at that level.
In Erlang programs, you'll find code like X2 = X1 + 1 all over. There are downsides to both approaches. José Valim made a conscious choice to allow rebinding of variables when he designed Elixir, and he wrote a blog post comparing the two approaches and the different bugs you run the risk of:
http://blog.plataformatec.com.br/2016/01/comparing-elixir-and-erlang-variables/
During the pattern matching, the values on the right of the match are assigned to their matched variables on the left:
iex(1)> {x, y} = {1, 2}
{1, 2}
iex(2)> x
1
iex(3)> y
2
On the right hand side, the values of the variables prior to the match are used. On the left, the variables are set.
You can force the left side to use a variable's value too, with the ^ pin operator:
iex(4)> x = 1
1
iex(5)> ^x = x + 1
** (MatchError) no match of right hand side value: 2
This fails because it's equivalent to 1 = 1 + 1, which is the failure condition you were expecting.

Prolog query fails

This is supposed to calculate the sum of two lists. The lists can be of different size.
sum([],[],[]).
sum(A,[],A).
sum([],B,B).
sum([A|Int1],[B|Int2],[C|Int3]) :-
(
C =:= A + B
;
((C =:= A), B = [])
;
((C =:= B), A = [])
),
sum(Int1,Int2,Int3).
It seems to work correctly, except when trying to find the sum of two lists. Then it gives the following error:
ERROR: =:=/2: Arguments are not sufficiently instantiated
I don't see why. There's a recursive and a basis step, what exactly is not yet instantiated and how do I fix it?
[1] While your disjunctions in the last clause are -- to some extent -- conceptually correct, Prolog considers these disjunctions in sequence. So it first considers C =:= A + B. But either A or B can be the empty list! This is what causes the error you reported, since the empty list is not allowed to occur in a numeric operation.
[2] You need to use C is A + b (assignment) i.o. C =:= A + B (numeric equivalence).
[3] If you say [A|Int1] and then A = [], then this means that [A|Int1] is not (only) a list of integers (as you claim it is) but (also) a list of lists! You probably intend to check whether the first or the second list is empty, not whether either contains the empty list.
Staying close to your original program, I would suggest to reorder and change things in the following way:
sumOf([], [], []):- !.
sumOf([], [B|Bs], [C|Cs]):- !,
C is B,
sumOf([], Bs, Cs).
sumOf([A|As], [], [C|Cs]):- !,
C is A,
sumOf(As, [], Cs).
sumOf([A|As], [B|Bs], [C|Cs]):-
C is A + B,
sumOf(As, Bs, Cs).
For example:
?- sumOf([1,2,3], [1,-90], X).
X = [2, -88, 3]
Notice my use of the cut (symbol !) in the above. This makes sure that the same answer is not given multiple times or -- more technically -- that no choicepoints are kept (and is called determinism).
You should read a tutorial or a book. Anyway, this is how you add two things to each other:
Result is A + B
This is how you could add all elements of one list:
sum([], 0). % because the sum of nothing is zero
sum([X|Xs], Sum) :-
sum(Xs, Sum0),
Sum is X + Sum0.
And this is how you could add the sums of a list of lists:
sums([], 0).
sums([L|Ls], Sums) :-
sums(Ls, Sums0),
sum(L, S),
Sums is Sums0 + S.

Resources