macros - 如何编写一个 DSL 来创建一个带参数的函数?
问题描述
我想定义一个宏,以便我可以将一个do
块传递给它,并让宏创建一个调用该块的函数,并带有一个参数。我遇到了鸡和蛋的问题,因为下面的代码抱怨name
没有定义。
defmodule MyMacro do
defmacro greet(do: block) do
quote do
def hello(name), do: unquote(block)
end
end
end
defmodule Test do
import MyMacro
greet do
IO.puts("Hello, #{name}!")
end
end
尝试编译此代码会导致:
(CompileError) iex:6: undefined function name/0
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
据我了解,这甚至在它到达我的宏之前就爆炸了,因为 elixir 在调用我的宏之前尝试为 do 块生成一个 AST,但name
未定义。
我的目标是能够Test.hello("world")
在编译 DSL 后调用。这在 Elixir 中可能吗?
解决方案
Elixir 的宏是卫生的,所以如果你在宏中声明一个变量,quote
调用者将无法使用它。您可以通过使用以下包装变量的声明来禁用此功能var!
:
quote do
def hello(var!(name)), do: unquote(block)
end
推荐阅读
- entity-framework-core - Entity Framework Core - 迁移从模型创建所有属性,而不是所需的
- c - 从二进制文件读取 C 编程
- php - Laravel retrieve data with condition from many-to-many condition
- python - 在 python 中绘制 x_n = A**n * x0
- mysql - 最大和计数连接 n 到 n 个表
- startup - 启动时的 Ngrok
- sql - 如何有效地按子查询的结果排序?
- django - modelForm 实例未通过
- ios - 在 iOS 13 中请求位置权限时出现奇怪的崩溃
- facebook - knpuniversity oauth2client 预期状态通常为空