2015-02-09 96 views
5

我能理解这一点:为什么Elixir允许使用未定义变量的闭包?

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 

我没有得到这么多的是,为什么是它允许药剂即使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 
+0

这是任何REPL中对于动态语言(例如我曾经使用过的Elixir)的常见行为(实际上并非如此)。也就是说,我在'Clojure'的'lein repl'中看到了相同的结果。 – ThanksForAllTheFish 2015-02-09 08:03:57

回答

10

这是在药剂中的错误将被固定在1.1版(已经在主分支):

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

3

有几个步骤,确定在二郎山函数时(和药剂,因为它是建立在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中,大多数语言特性都是作为宏来实现的,所以最后一步不是在函数定义期间,而是在调用时。我不确定,如果你能够检查,如果所有变量都被绑定在宏定义中。如果可能的话 - 那将是一个很酷的解决方案。

相关问题