继续使用药剂文档中的绑定和引号片段示例..。
我们有一个宏,它基于关键字列表定义函数。
defmodule MacroFun do
defmacro defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
end
defmodule Runner do
require MacroFun
kv = [foo: 1, bar: 2]
MacroFun.defkv(kv)
end
Runner.foo现在,让我们将宏的主体移到助手函数中。
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end太好了,一切都还能用。但是,如果我们想在将kv传递给私有助手函数之前,再创建另一个修改它的宏,该怎么办:
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
_defkv(modified_kv)
end
end那不管用。灵丹妙药说,_devkv没有定义。我们可以通过使用完全限定的函数名来修复:
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
MacroFun._defkv(modified_kv)
end
end但随后,她抱怨说,MacroFun._defkv是私有的。因此,我们将其更改为public,但它仍然不起作用,因为helper方法_devkv将引用的代码返回给我们的宏def_modified_kv,这个宏本身就是引用的!
因此,我们可以通过对助手函数返回的代码(最终代码)来修复这个问题:
defmodule MacroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
MacroFun._defkv(modified_kv) |> Code.eval_quoted([], __ENV__) |> elem(0)
end
end
def _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
endCode.eval_quoted之外,还有更好的方法来做到这一点吗?我觉得我做错了什么。
谢谢你的帮助。
发布于 2016-01-24 05:37:17
SomeOtherModule中定义),则是宏展开的上下文。在SomeOtherModule中,您需要import MacroFun在本地调用它的函数。下面的代码在Elixir >= 1.2.0中工作
例如。
defmodule MacroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
defkv(modified_kv)
end
end
end
defmodule Runner do
import MacroFun
kv = [foo: 1, bar: 2]
def_modified_kv(kv)
end希望这能回答你的问题!祝好运。
更新了几次,因为宏有点混乱!
发布于 2016-01-25 10:37:52
1)通过使用require,您已经告诉编译器编译并提供MacroFun的公共宏和函数。请注意,函数无论如何都是可用的:
注意,通常在使用之前不应该需要模块,唯一的例外是如果您想使用模块中的宏。
2)它们可通过其FQN获得
3)以下是我对此的看法:
defmodule MicroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k,v} ->
def unquote(k)(), do: unquote(v)
end
end
end
defmacro modifier(kv) do
quote bind_quoted: [kv: kv] do
Enum.map kv, fn {k,v} -> {k, v+1} end
end
end
end
defmodule Runner do
require MicroFun
[foo: 1, bar: 2]
|> MicroFun.modifier
|> MicroFun.defkv
end这样做的想法是,您不需要嵌套宏/函数时,您可以只是管道。
https://stackoverflow.com/questions/34892313
复制相似问题