Elixir匿名函数,捕获和部分应用程序

tom*_*ave 2 elixir

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

我注意到了我认为令人惊讶的行为.例如,我观察到此代码段中的最后一个表达式返回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
Run Code Online (Sandbox Code Playgroud)

我将其解释为意味着"重新创建"动态匿名函数会&(&1 <> "-X")返回一个值,该值不等于存储的值f(根据==语义).

那没关系,这个其他片段将证实我的理论:

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

is_function g
# true

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

g == &(String.upcase(&1))
# true
Run Code Online (Sandbox Code Playgroud)

在那里,g将等于重新创建的匿名函数,因为 - 可能 - 捕获现有的命名函数由编译器优化,并且每次返回相同的值.第二个片段中第一行的返回值似乎证实了两种情况的区别对待.

然后我尝试使用"已知"函数,这意味着它已经存在:

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

z == &(f.(&1))
# false
Run Code Online (Sandbox Code Playgroud)

最后一句话再次是假的.
我本来希望&(f.(&1))以类似的方式对待&(String.upcase(&1)),因为两者都已存在.

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

mic*_*ala 5

你是对的,因为捕获命名函数是优化的,因此每次都返回相同的值.

再往下我经常通过"funs"引用匿名函数,通过"mfa"引用函数的模块,函数和arity.

捕获一个众所周知的匿名函数时没有相等性的事实与优化的工作方式有关.当从命名函数创建乐趣而不是存储整个匿名函数时,编译器存储模块名称,函数名称和命名函数的arity.通过"重新捕获"一个众所周知的匿名函数是不可能的 - 每次都必须创造新的乐趣.

免责声明:本分析不是基于编译器的深厚知识,但熟悉的外部术语格式(调用的结果:erlang.term_to_binary/1),这是在描述http://erlang.org/doc/apps/erts/erl_ext_dist.html.

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

  • FUN_EXT/NEW_FUN_EXT - 编码一般匿名函数.这基本上编码了对特定模块(乐趣定义的模块)有趣表的引用.
  • EXPORT_EXT - 以模块名称,函数名称和arity的形式对命名函数中的匿名函数进行编码.

这还可以深入了解匿名函数的实现方式:每个模块都有一个表格,其中包含内部发生的所有匿名函数.我怀疑编译器正在进行一些lambda提升以构造这样一个表.从命名函数创建的函数编码方式不同 - 作为mfa并且可能不存储在fun表中.