【问题标题】:Elixir anonymous functions, captures, and partial applicationsElixir 匿名函数、捕获和部分应用程序
【发布时间】:2016-10-04 17:01:51
【问题描述】:

我正在学习 Elixir,目前正在处理捕获的语义和函数的部分应用。
我已经熟悉fn(x)-> x + 1 end 语法。

我注意到我认为令人惊讶的行为。例如,我观察到这个 sn-p 中的最后一个表达式返回 false

f = &(&1 <> "-X")
# #Function<6.50752066/1 in :erl_eval.expr/5>

is_function f
# true

is_function &(&1 <> "-X")
# true

f == &(&1 <> "-X")
# false

我将其解释为动态“重新创建”匿名函数&amp;(&amp;1 &lt;&gt; "-X") 返回的值不等于存储在f 中的值(根据== 语义)。

那很好,另一个 sn-p 将证实我的理论:

g = &(String.upcase(&1))
# &String.upcase/1

is_function g
# true

is_function &(String.upcase(&1))
# true

g == &(String.upcase(&1))
# true

在那里,g 将等于重新创建的匿名函数,因为——也许——捕获现有的命名函数已被编译器优化,并且每次都返回相同的值。第二个 sn-p 中第一行的返回值似乎证实了两种情况不同处理的想法。

然后我尝试使用“已知”功能,这意味着它已经存在:

f = &(&1 <> "-X")
z = &(f.(&1))
#Function<6.50752066/1 in :erl_eval.expr/5>

z == &(f.(&1))
# false

最后一句话又是假的。
我本来希望&amp;(f.(&amp;1)) 以与&amp;(String.upcase(&amp;1)) 类似的方式处理,因为两者都已经存在。

那么,函数捕获的语义是什么?

【问题讨论】:

    标签: elixir


    【解决方案1】:

    你说得对,捕获命名函数是经过优化的,因此每次都返回相同的值。

    往下说,我经常用“funs”来指代匿名函数,用“mfa”来指代模块、函数和函数的数量。

    为什么在捕获众所周知的匿名函数时不存在相等的事实与优化的工作原理有关。当从命名函数创建 fun 而不是存储整个匿名函数时,编译器会存储模块名称、函数名称和命名函数的数量。 “重新捕获”一个众所周知的匿名函数是不可能的——你必须每次都创造一个新的乐趣。

    免责声明:此分析不是基于对编译器的深入了解,而是对外部术语格式的熟悉(调用:erlang.term_to_binary/1 的结果),在http://erlang.org/doc/apps/erts/erl_ext_dist.html 中有描述。

    ETF 中有两种不同的匿名函数类型:

    • FUN_EXT/NEW_FUN_EXT - 编码通用匿名函数。这基本上编码了对特定模块(定义乐趣的模块)乐趣表的引用。
    • EXPORT_EXT - 以模块名称、函数名称和数量的形式从命名函数编码匿名函数。

    这也让我们深入了解匿名函数是如何实现的:每个模块都有一个包含内部出现的所有匿名函数的表。我怀疑编译器正在执行某种 lambda 提升以构造这样的表。从命名函数创建的 funs 编码不同 - 作为 mfa 并且可能不存储在 fun 表中。

    【讨论】:

      猜你喜欢
      • 2016-08-31
      • 2014-03-25
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 2018-08-16
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      相关资源
      最近更新 更多