为什么 Elixir 允许带有未定义变量的闭包?
Why does Elixir allow closures with undefined variables?
我能理解这个:
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 允许定义打印函数,即使 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
在 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 中,大多数语言特性都是作为宏实现的,所以最后一步不是在函数定义时执行的,而是在调用时执行的。我不确定,如果你能够检查,是否所有变量都绑定在宏定义中。如果可能 - 那将是很酷的解决方案。
这是 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
了
我能理解这个:
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 允许定义打印函数,即使 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
在 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 中,大多数语言特性都是作为宏实现的,所以最后一步不是在函数定义时执行的,而是在调用时执行的。我不确定,如果你能够检查,是否所有变量都绑定在宏定义中。如果可能 - 那将是很酷的解决方案。
这是 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
了