我正在学习Elixir(在Ruby中有一些exp,JS)。有一个有趣的问题。只是出于好奇和更好地理解函数式编程。
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'如果'宏不承认"这个"很好吃元组" ?
是出于目的吗?
答案 0 :(得分:3)
if
宏是macro, accepting a keyword list个参数。允许使用两种可能的变体:仅显示do
个密钥,同时显示do
和else
(下面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中有一个特殊的含义,因为有人可能会通过一个块,这就是为什么它在所有宏扩展之前被处理,而且你甚至无法嵌入关键字列表,因为你已尝试过另一个宏。