如何使用宏创建一个带有警卫的匿名函数?

时间:2016-06-15 12:38:52

标签: elixir

我一直在研究宏来动态生成匿名函数。该函数应该有2个子句。当守卫满意时,第一个子句返回TRUE。然而,第二个是默认值,如果与第一个子句不匹配,则返回FALSE。例如:

fn 
  xfield when xfield > 2 -> true
  _ -> false
end

这是我的宏原型

defmacro condition_function(field, guard) do
  clause1 =  quote do: (unquote(field) when unquote(guard) -> true)
  clause2 =  quote do: (_ -> false)
  fun_clauses =  clause1 ++ clause2
  {:fn, [], fun_clauses}
end

问题是第一个子句从不匹配。这是我用来在Elixir的REPL中测试我的宏的输入:

iex(84)> myfield = quote do: xfield
{:xfield, [], Elixir}
iex(85)> myguard = quote do: xfield > 2
{:>, [context: Elixir, import: Kernel], [{:xfield, [], Elixir}, 2]}
iex(86)> myFun = Builder.condition_function(myfield, myguard)
#Function<6.50752066/1 in :erl_eval.expr/5>
iex(87)> myFun.(2)
false
iex(88)> myFun.(5)
false

有什么建议吗?

提前致谢, 温贝托

2 个答案:

答案 0 :(得分:2)

我解决了我的问题,感谢slack频道和CoderDennis小费的帮助。

这是我的误解。我不需要使用宏。我只需要一个常规功能。

这是我用函数创建匿名函数的函数的最终版本:

def anonym_function(field, constraint) do
    clause1 =  quote do: (unquote(field) when unquote(constraint) -> true)
    clause2 =  quote do: (_ -> false)
    fun_clauses =  clause1 ++ clause2
    {fun, _} = Code.eval_quoted({:fn, [], fun_clauses})
    fun
end

对不起我的误解:(

答案 1 :(得分:1)

我还没有完整的答案,但是这里是如何看到你的宏回归的AST:

defmacro condition_function(field, guard) do
  clause1 =  quote do: (unquote(field) when unquote(guard) -> true)
  clause2 =  quote do: (_ -> false)
  fun_clauses =  clause1 ++ clause2
  result = {:fn, [], fun_clauses}
  IO.inspect(result)
  result
end

这是我从iex中引用匿名函数得到的结果。这可能是宏应该生成的内容:

iex> quote do: fn
...> xfield when xfield > 2 -> true
...> _ -> false
...> end
{:fn, [],
 [{:->, [],
   [[{:when, [],
      [{:xfield, [], Elixir},
       {:>, [context: Elixir, import: Kernel], [{:xfield, [], Elixir}, 2]}]}],
    true]}, {:->, [], [[{:_, [], Elixir}], false]}]}

这是我在实际执行包含IO.inspect的宏时得到的结果:

iex(9)> myFun = Builder.condition_function(myfield, myguard)
{:fn, [],
 [{:->, [],
   [[{:when, [], [{:myfield, [line: 9], nil}, {:myguard, [line: 9], nil}]}],
    true]}, {:->, [], [[{:_, [], Builder}], false]}]}

(第9行是指iex中的行号。)

这告诉我们unquote(myfield)unquote(myguard)没有做您希望他们在您的宏中做的事情。

我不是一个宏观专家知道如何做你想做的事情,但我只是想分享我的宏调试技巧。如果我能找到使其发挥作用的方法,我也会分享它。