【发布时间】:2019-03-19 23:22:12
【问题描述】:
我读到的关于 Elixir 的所有内容都说赋值应该被认为是模式匹配。如果是这样,那么为什么 x = x + 1 在 Elixir 中起作用?没有 x = x + 1 的 x 值。
【问题讨论】:
-
因为 Elixir 完全没有抓住重点。尽可能使用 Erlang。少得多的混乱。
标签: functional-programming elixir
我读到的关于 Elixir 的所有内容都说赋值应该被认为是模式匹配。如果是这样,那么为什么 x = x + 1 在 Elixir 中起作用?没有 x = x + 1 的 x 值。
【问题讨论】:
标签: functional-programming elixir
我读到的所有关于 Elixir 的文章都说赋值应该被认为是模式匹配。
在 Elixir 中,= 是 称为模式匹配运算符,但它的工作方式与 Erlang 中的模式匹配运算符不同。这是因为 Elixir 中的变量不像 Erlang 中那样是单一赋值。以下是 Erlang 的工作方式:
~/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>
因此,在 Erlang 中这会失败:
4> X = X + 1.
** exception error: no match of right hand side value 16
Erlang 的单一赋值非常简单:因为 X 已经有一个值,X = X + 1 行不能尝试为 X 分配一个新值,所以该行是模式匹配的尝试 (15 = 15 + 1) ,这将永远失败。
另一方面,Elixir 中的变量不是单一赋值:
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)>
Elixir 中变量不是单一赋值的事实意味着 Elixir 需要在编写时做出选择:
x = 10
x = x + 1 #or even x = 15
选择 1) 是否应该将第二行解释为对 x 的赋值?
选项 2)是否应该将第二行解释为模式匹配的尝试(即10 = 11)?
Elixir 与选择 1 一起使用。这意味着实际上使用 Elixir 中所谓的模式匹配运算符执行模式匹配更加困难:您必须将 pin 运算符 (^) 与匹配运算符 (@ 987654331@):
x = 10
^x = x + 1
现在,第二行总是会失败。如果您想在不使用 pin 运算符的情况下执行模式匹配,还有一个技巧在某些情况下会起作用:
x = 10
12 = x
在第二行中,您将变量放在右侧。我认为规则可以这样表述:在模式匹配运算符(=)的右侧,始终评估变量,即用它们的值替换。左边的变量总是被赋值给——除非使用了 pin 操作符,在这种情况下,一个固定的变量被它的当前值替换,然后与右边的模式匹配。因此,将 Elixir 的 = 运算符称为混合赋值/模式匹配运算符可能更准确。
【讨论】:
您可以想象x = x + 1 被编译器重写为x2 = x1 + 1 之类的东西。
这与它的工作原理非常接近。这不是我在这里使用的简单索引号,但概念是相同的。 BEAM 看到的变量是不可变的,并且在该级别不会进行重新绑定。
在 Erlang 程序中,你会发现到处都是 X2 = X1 + 1 这样的代码。这两种方法都有缺点。 José Valim 在设计 Elixir 时有意识地选择允许重新绑定变量,他写了一篇博文比较了这两种方法以及您可能面临的不同错误:
http://blog.plataformatec.com.br/2016/01/comparing-elixir-and-erlang-variables/
【讨论】:
在模式匹配过程中,匹配右侧的值被分配到其匹配的左侧变量:
iex(1)> {x, y} = {1, 2}
{1, 2}
iex(2)> x
1
iex(3)> y
2
在右侧,使用匹配之前的变量值。在左侧,设置了变量。
您也可以通过^ pin operator 强制左侧使用变量的值:
iex(4)> x = 1
1
iex(5)> ^x = x + 1
** (MatchError) no match of right hand side value: 2
这会失败,因为它等同于 1 = 1 + 1,这是您所期望的失败条件。
【讨论】: