在列表理解中重新分配变量

Abh*_*k S 4 functional-programming list-comprehension elixir

我是 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
Run Code Online (Sandbox Code Playgroud)
  1. 为什么这些函数的行为不同?
  2. 这是 Elixir 中的变量作用域还是我所缺少的函数式编程的基本原则?

Jos*_*lim 5

这是 Elixir 中的变量作用域还是我所缺少的函数式编程的基本原则?

实际上两者都是。

Elixir 只允许在相同作用域和所有构造中重新绑定,但casecond和除外receive,引入新的作用域。一些例子:

num = 1

try do
  num = 2
after
  num = 3
end

num #=> 1
Run Code Online (Sandbox Code Playgroud)

乐趣:

num = 1
(fn -> num = 2 end).()
num #=> 1
Run Code Online (Sandbox Code Playgroud)

现在举一些规则例外的例子:

num = 1
case true do
  true -> num = 2
end
num #=> 2

num = 1
cond do
  true -> num = 2
end
num #=> 2
Run Code Online (Sandbox Code Playgroud)

尽管如此,上述情况有些不鼓励,因为最好显式返回值:

num = 1
case x do
  true  -> 2
  false -> num
end
#=> will return 1 or 2
Run Code Online (Sandbox Code Playgroud)

上面的示例明确了从 case 返回的值是什么。为什么 Elixir 中支持这些,尽管不推荐,这是一个很长的故事,它起源于 Erlang,并由于 Elixir 中的一些(很少)命令式宏而继续存在,例如ifunless。随着我们迈向 Elixir 2.0,它可能会发生变化。

执行您想要的操作的最佳方法是通过 中的函数Enum。您的特定示例可以用它来完成Enum.sum/1,但任何其他复杂的示例都可以用它来实现Enum.reduce/3(枚举中的几乎所有函数都是用reduce 来实现的,这可能会在其他语言中折叠)。