为什么x = x +1在Elixir中有效?

iph*_*007 5 functional-programming elixir

我所阅读的有关Elixir的所有内容都表明,应将作业视为模式匹配。如果是这样,那么为什么x = x + 1在Elixir中起作用?对于x = x + 1没有x的值。

7st*_*tud 6

我所阅读的有关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> 
Run Code Online (Sandbox Code Playgroud)

因此,在Erlang中这将失败:

4> X = X + 1.
** exception error: no match of right hand side value 16
Run Code Online (Sandbox Code Playgroud)

使用Erlang的单次分配,事情很简单:因为X已经有一个值,所以该行X = X + 1不能试图为X赋一个新值,因此该行是试图对match(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)> 
Run Code Online (Sandbox Code Playgroud)

变量不是Elixir中的单个赋值,这一事实意味着Elixir在编写时需要做出选择:

x = 10
x = x + 1  #or even x = 15
Run Code Online (Sandbox Code Playgroud)

选择1)第二行应解释为的赋值x吗?
选择2)第二行是否应该解释为尝试模式匹配(即10 = 11)?

Elixir带有Choice1。这意味着用Elixir中的所谓模式匹配运算符实际执行模式匹配更为困难:您必须将pin运算符(^)与match operator(=)结合使用:

x = 10
^x = x + 1  
Run Code Online (Sandbox Code Playgroud)

现在,第二行将始终失败。如果您想在不使用pin运算符的情况下执行模式匹配,还有一种技巧在某些情况下会起作用:

x = 10
12 = x
Run Code Online (Sandbox Code Playgroud)

在第二行中,将变量放在右侧。我认为规则可以这样表示:在模式匹配操作符(=)的右侧,总是对变量求值,即用其值替换。始终在左侧分配变量-除非使用pin运算符,否则在这种情况下,固定变量将替换为其当前值,然后在右侧进行模式匹配。结果,将Elixir的=运算符称为混合分配/模式匹配运算符可能更准确。


Ada*_*hip 5

在模式匹配期间,匹配右侧的值被分配给左侧的匹配变量:

iex(1)> {x, y} = {1, 2}
{1, 2}
iex(2)> x
1
iex(3)> y
2
Run Code Online (Sandbox Code Playgroud)

在右侧,使用匹配之前变量的值。在左侧,设置了变量。

您也可以使用^pin 运算符强制左侧使用变量的值:

iex(4)> x = 1
1
iex(5)> ^x = x + 1
** (MatchError) no match of right hand side value: 2
Run Code Online (Sandbox Code Playgroud)

这将失败,因为它等效于1 = 1 + 1,这是您期望的失败条件。


Mar*_*lin 5

您可以想象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/