我一直在研究宏来动态生成匿名函数。该函数应该有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
有什么建议吗?
提前致谢, 温贝托
答案 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)
没有做您希望他们在您的宏中做的事情。
我不是一个宏观专家知道如何做你想做的事情,但我只是想分享我的宏调试技巧。如果我能找到使其发挥作用的方法,我也会分享它。