【问题标题】:Why does Elixir allow closures with undefined variables?为什么 Elixir 允许带有未定义变量的闭包?
【发布时间】:2015-02-09 19:47:37
【问题描述】:

我可以理解:

iex(7)> outside_val = 5
5
iex(8)> print = fn() -> IO.puts(outside_val) end
#Function<20.90072148/0 in :erl_eval.expr/5>
iex(9)> print.()  
5
:ok

我不太明白的是,为什么 Elixir 允许定义 print 函数,即使未定义 outside_val 并且以后只会出错?无论如何,在定义了闭包之后就无法传入“outside_val”,所以 Elixir 在创建过程中检查变量是否存在不是更好吗?

我的意思是:

iex(2)> print = fn () -> IO.puts(outside_val) end
#Function<20.90072148/0 in :erl_eval.expr/5>
iex(3)> outside_val = 5
5
iex(4)> print.()
** (RuntimeError) undefined function: outside_val/0

【问题讨论】:

  • 这是我曾经使用过的动态语言的任何 REPL 中的常见行为,例如 Elixir(实际上并不多)。即,我在lein repl 中看到与Clojure 相同的结果。

标签: elixir


【解决方案1】:

这是 Elixir 中的一个错误,将在 v1.1 中修复(已经在 master 分支中):

Interactive Elixir (1.1.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> print = fn () -> IO.puts(outside_val) end
** (CompileError) iex:1: undefined function outside_val/0

当前实现延迟扩展以调用IEx.Helpers 中的函数。在master中,我们只需要导入IEx.Helpers,以后就不需要再扩展outside_val了。

【讨论】:

    【解决方案2】:

    在 Erlang 中定义一个函数时有几个步骤(在 Elixir 中,因为它是建立在 ErlangVM 之上的)。

    首先,您将输入标记化:

    {ok, Ts, _} = erl_scan:string("fun() -> Z + 1 end.").
    

    然后,创建抽象语法树:

    {ok, [ListAST]} = erl_parse:parse_exprs(Ts).
    

    最后一步是评估它:

    Bindings = [{'Z', 1}].
    erl_eval:expr(ListAST, Bindings).
    

    在最后一步,Erlang 可以看到,存在未定义的变量并引发异常。

    在 Elixir 中,大多数语言功能都是以宏的形式实现的,因此最后一步不是在函数定义期间执行,而是在调用时执行。我不确定,如果您能够检查,是否所有变量都绑定在宏定义中。如果可能的话 - 那将是一个很酷的解决方案。

    【讨论】:

      猜你喜欢
      • 2019-04-17
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 2021-11-12
      • 2020-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多