Elixir 为什么是长生不老药';如果';宏不接受与元组{:do,“true part”匹配的变量?

Elixir 为什么是长生不老药';如果';宏不接受与元组{:do,“true part”匹配的变量?,elixir,Elixir,我正在学习长生不老药(在Ruby,JS中有一些经验)。我有一个有趣的问题。只是出于好奇,为了更好地理解函数式编程 从: 提供一个if/2宏。 此宏要求第一个参数为条件,第二个参数为关键字列表 换句话说,我可以写: if(true, [do: "true stuff", else: "false stuff"]) # => "true stuff" 这条线工作得很好。嗯 但据我所知,关键字列表是元组列表。所以我试过: if(true, [{:do, "true stuff"}, {:els

我正在学习长生不老药(在Ruby,JS中有一些经验)。我有一个有趣的问题。只是出于好奇,为了更好地理解函数式编程

从:

提供一个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的“如果”宏不“识别”这个“好吃的元组”


这样的事情是故意的吗?

如果宏是一个参数。允许有两种可能的变体:仅显示
do
键,同时显示
do
else
(以下4行)

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

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

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中有一个特殊的含义,因为人们可能会用它传递一个块,这就是为什么它在所有宏扩展之前都会被处理,甚至不能像你用另一个宏尝试过的那样嵌入关键字列表。

感谢@mudasobwa为我指出
引号
。我检查过长生不老药。下一步,我检查了宏。然后找出下面几行:“…函数调用的参数在调用函数之前进行求值。但是,宏不求值它们的参数。相反,它们以引用表达式的形式接收参数…”。这句话,加上你的回答,一起向我解释我的疑问。
iex> var = [a: 42]
iex> quote do: var
{:var, [], Elixir}