丹药功能评价

Elixir Function Evaluation

Elixir 语言的新手,我非常欣赏简洁的语法和强大的运行环境。

下面简单的问题是get_horizontal_line()函数在什么情况下会被重新求值?

我在学习这门语言时遇到的更广泛的问题是关于执行环境和编译器优化。我正在慢慢地阅读 Elixir 文档,接下来我打算阅读 Erlang 文档,然后我正在寻找有关运行时环境 (VM) 的信息。

有没有人推荐去哪里了解更多关于 VM 系统架构和编译器的信息?在查看 Erlang VM 源代码之前。

def get_horizontal_line, do: String.duplicate("-", 80)
def get_horizontal_line(n), do: String.duplicate("-", n)

# Binds the result of calling the function but does not execute it to determine the result.
x = get_horizontal_line()
y = get_horizontal_line()

# Forces evaluation of the function.
IO.puts(x)

# Does this force re-evaluation?
IO.puts(y)

# Binds the result of calling the function but does not execute it to determine the result.
x = get_horizontal_line(80)
y = get_horizontal_line(80)

# Forces evaluation of the function.
IO.puts(x)

# Does this force re-evaluation?
IO.puts(y)

def get_horizontal_line, 执行: String.duplicate("-", 80) def get_horizontal_line(n), 做: String.duplicate("-", n)

这用一个子句定义了两个函数。第一个函数不带参数,第二个函数带参数。

# Binds the result of calling the function but does not execute it to determine the result.
x = get_horizontal_line()
y = get_horizontal_line()

这两个表达式都会计算对 get_horizontal_line 的函数调用。所以我不确定你的意思是“不执行它”。 Elixir 中没有惰性求值。 此时get_horizontal_line函数已经被调用执行了两次

# Forces evaluation of the function.
IO.puts(x)

变量 x 已经绑定到上面 get_horizontal_line() 的结果,所以这只是打印它的值。

# Does this force re-evaluation?
IO.puts(y)

变量 y 已经绑定到上面 get_horizontal_line() 的结果,所以这只是打印它的值。

# Binds the result of calling the function but does not execute it to determine the result.
x = get_horizontal_line(80)
y = get_horizontal_line(80)

# Forces evaluation of the function.
IO.puts(x)

# Does this force re-evaluation?
IO.puts(y)

这与上面的行为相同。

我不知道这是否回答了你的问题。

关于学习更多关于 Erlang VM 的信息,强烈推荐免费的 BEAM 一书[1]。

[1] https://github.com/happi/theBeamBook

也许如果我们使用不同的例子,我们可以更清楚地看到它是如何工作的。考虑以下因素:

defmodule Foo do
  def bar, do: DateTime.utc_now()
end

x = Foo.bar()
y = Foo.bar()

Process.sleep(1_000)

IO.puts("#{x} executed 1 second before #{DateTime.utc_now()}")
IO.puts("#{y} executed mere microseconds after #{x}")

产生如下输出:

2021-09-10 15:50:54.996566Z executed 1 second before 2021-09-10 15:50:56.000597Z
2021-09-10 15:50:54.998613Z executed mere microseconds after 2021-09-10 15:50:54.996566Z

您会注意到对 Foo.bar/0 的调用在它们出现的 运行 时间执行(即当它们的输出被分配给一个变量时)。您可以看到 xy 并不 相同 ,但是您可以看到 Foo.bar/0 执行得尽可能快。

可能值得一提的是:当一个函数在模块内部浮动的某个地方被调用时(而不是从另一个函数 do/end 块中调用),它会在 compile 处执行time(不是在 运行 时间)。我最常在绑定模块属性时看到这个:

defmodule Foo do
  @x some_function()
end

在读取应用程序配置时,这是一个很大的问题(作为一个示例),Elixir 现在会在您尝试在编译时评估的地方使用 Application.get_env/3 时发出警告。

这个答案只是为了澄清你的问题重新编码评估的第一部分。最好将有关编译器优化和 Erlang VM 的问题留给他们自己的专用问题。