What is the exact meaning of the equal sign in Elixir?

Deadly 提交于 2021-02-05 06:18:46

问题


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.


回答1:


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?




回答2:


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



回答3:


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)


来源:https://stackoverflow.com/questions/38015711/what-is-the-exact-meaning-of-the-equal-sign-in-elixir

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!