我是Elixir的新手和来自OO背景的函数式编程。
我试图理解列表理解中Elixir中的变量重新分配是如何工作的。我期望函数test1()和test2()打印4,但test2()没有重新分配变量并打印1。
defmodule SampleCode do
def test1 do
num = 1
num = num + 1
num = num + 2
IO.puts num # Prints 4
end
def test2 do
num = 1
for i <- (1..2) do
num = num + i
end
IO.puts num # Prints 1
end
end
答案 0 :(得分:4)
这是Elixir中的变量范围内容还是我缺少的函数式编程的基本原理?
实际上都是。
Elixir仅允许在同一范围和所有构造中重新绑定,${#session.['CurrentUser'].farsiFirstName}
${#session.CurrentUser.farsiFirstName}
,case
和cond
除外,引入新范围。一些例子:
receive
玩意儿:
num = 1
try do
num = 2
after
num = 3
end
num #=> 1
现在规则例外的一些例子:
num = 1
(fn -> num = 2 end).()
num #=> 1
尽管如此,上述情况有些不鼓励,因为最好明确地返回值:
num = 1
case true do
true -> num = 2
end
num #=> 2
num = 1
cond do
true -> num = 2
end
num #=> 2
上面的示例明确了从case返回的值是什么。为什么那些在Elixir中得到支持,即使不推荐,也是一个长篇故事,它起源于Erlang,并且由于Elixir中的一些(极少数)命令性宏,如num = 1
case x do
true -> 2
false -> num
end
#=> will return 1 or 2
和if
而继续存在。随着我们向Elixir 2.0迈进,它可能会发生变化。
执行所需内容的最佳方式是通过unless
中的功能。您的特定示例可以使用Enum
完成,但任何其他复杂示例都可以使用Enum.sum/1
来实现(Enum中的几乎所有函数都是以reduce语言实现的,可能会在其他语言中实现)。
答案 1 :(得分:4)
要了解发生了什么,请查看elixir对您的代码所做的操作,以便在语法*不支持时语法允许重新绑定:
BEFORE AFTER
defmodule SampleCode do | defmodule SampleCode do
def test1 do | def test1 do
num = 1 | num_1 = 1
num = num + 1 | num_2 = num_1 + 1
num = num + 2 | num_3 = num_2 + 2
IO.puts num # Prints 4 | IO.puts num_3
end | end
|
def test2 do | def test2
num = 1 | num_1 = 1
for i <- (1..2) do | for i <- (1..2) do
num = num + i | num_2 = num_1 + i
end | end
IO.puts num # Prints 1 | IO.puts num_1
end | end
end | end
* Elixir的基础是Erlang-Elixir的编译产生Erlang .beam文件,由Erlang虚拟机执行。 Erlang不允许变量重新绑定,因此 Elixir在编译期间交换变量名称。
如果你想要提高你的FP游戏,并在编写Elixir时给自己一个巨大的支持,我建议你强迫自己学习Erlang语法,并在一个月或几个月内严格写出你的问题的Erlang解决方案在回到Elixir之前。
如果你很好奇你的代码实际发生了什么,这里是Elixir生成的实际Erlang:
1: test1() ->
2: num@1 = 1,
3: num@2 = num@1 + 1,
4: num@3 = num@2 + 2,
5: 'Elixir.IO':puts(num@3).
6: test2() ->
7: num@1 = 1,
8: 'Elixir.Enum':reduce(#{'__struct__' => 'Elixir.Range',
9: first => 1, last => 2},
10: [], fun (i@1, _@1) -> num@2 = num@1 + i@1 end),
11: 'Elixir.IO':puts(num@1).
特别注意第11行 - 它引用的唯一变量是num@1
,在Erlang中不能被第8-10行更改 - 无论在那里发生什么,绑定到num@1
的值仍然是1
,因为它是第一行绑定在第7行的。