为什么Elixir' if'宏不接受与元组匹配的变量{:do," true part"}?

时间:2017-01-20 18:11:14

标签: elixir

我正在学习Elixir(在Ruby中有一些exp,JS)。有一个有趣的问题。只是出于好奇和更好地理解函数式编程。

来自documentation

if(condition, clauses)
  

提供if / 2宏。   该宏期望第一个参数是条件,第二个参数是关键字列表。

换句话说,我可以写:

if(true, [do: "true stuff", else: "false stuff"]) # => "true stuff"

这条线很完美。确定。

但据我所知,关键字列表是元组列表。所以我试过了:

if(true, [{:do, "true stuff"}, {:else, "false stuff"}]) # => "true stuff"

还在工作!

好。让我们做下一步:

var = "true stuff"
if( true, [{:do, var}, {:else, "false stuff"}]) # => "true stuff"

尼斯。现在让我们疯了!

var = {:do, "true stuff"}
if( true, [var, {:else, "false stuff"}])

** (ArgumentError) invalid or duplicate keys for if, only "do" and an optional "else" are permitted
   (elixir) lib/kernel.ex:2569: Kernel.build_if/2
   (elixir) expanding macro: Kernel.if/2
            iex:18: (file)

糟糕!

如果我们只是尝试在iex'一切都很好:

var = {:do, "true stuff"}
[var] # => [do: "true stuff"] 

为什么Elixir'如果'宏不承认"这个"很好吃元组" ?

是出于目的吗?

1 个答案:

答案 0 :(得分:3)

if宏是macro, accepting a keyword list个参数。允许使用两种可能的变体:仅显示do个密钥,同时显示doelse(下面4行)。

所有其他调用都与您看到的raises an exception子句直接匹配。

现在让我们了解关键字列表的工作原理:

iex> quote do: [a: 42]
[a: 42]
iex> quote do: [{:a, 42}]
[a: 42]

他们是一样的!但没有人会为你解码var:

iex> var = [a: 42]
iex> quote do: var
{:var, [], Elixir}

do子句在Elixir中有一个特殊的含义,因为有人可能会通过一个块,这就是为什么它在所有宏扩展之前被处理,而且你甚至无法嵌入关键字列表,因为你已尝试过另一个宏。