Reputation: 4484
Matching into the same variable, with the same value. This works:
iex(21)> {a, a} = {1, 1}
{1, 1}
Matching into the same variable, different values. Those do not:
iex(22)> {a, a} = {1, 2}
** (MatchError) no match of right hand side value: {1, 2}
iex(22)> {a, a} = {2, 1}
** (MatchError) no match of right hand side value: {2, 1}
I can understand when using the operator ^ why this works:
iex(22)> b = 1
1
iex(23)> {a, ^b} = {1, 1}
{1, 1}
But I'm a bit confused as to why this does not:
iex(24)> a = 2
2
iex(25)> {a, ^a} = {1, 1}
** (MatchError) no match of right hand side value: {1, 1}
My first thought was that the last example would work. If the internal mechanism is doing behind the scene a placement of the variable and then using its value for the next matching when matching on the same variable like in the first example.
I am curious as to how does the pattern matching on multiples of the same variable works internally in Elixir?
Upvotes: 2
Views: 123
Reputation: 13837
Interestingly enough, you can match the pinned value of a
and also rebind a
in the same line like this:
iex> a = 2
2
iex> {a, ^a} = {1, 2}
{1, 2}
iex> a
1
In that case ^a
matches the previously bound value for a
(which is 2) and a
is rebound to 1
to make the match.
Based on that result, the matching happens before the rebinding, but I wouldn't recommend doing something like that because it would be unclear what was actually happening.
Upvotes: 2
Reputation: 15293
Others may have a deeper insight into what happens but this is my mental model of this statement:
{a, a} = {1,1}
First consider this slightly simpler case:
a = 1
In this case it's a combination of an assertion and a binding. That is, if binding 1 to a will make the statement true then that happens. Contrast this with
^a = 1
The pin does not allow rebinding so if a
already has a value, if it's not 1 then the match will fail. Also if you try that statement before a
has been bound to a value, you'll get this error: ** (CompileError) iex:1: unbound variable ^a
So in the case of your tuple, I believe what's going on under the hood, so to speak, is that first a
is bound to 1
. Then the second a
in the expression has already been bound to 1
so when it tries to match it to 2
, that fails. That is, the binding only happens if the value in question (a
in this case) isn't already bound to something else. It's helpful to think of it as actually being two steps--a binding step and then a matching step.
Upvotes: 2
Reputation: 15736
Well, I am not sure what you expected from
{a, a} = {1, 2}
considering that you are trying to bind two different values to the same variable.
Regarding the second part, as you mentioned yourself, the ^ operator uses the value of the variable to pattern match against so when you do
a = 2
{a, ^a} = {1, 1}
it's pretty much the same as
{a, 2} = {1, 1}
and obviously 2 != 1 and therefore there is no match
Upvotes: 3