准引用宏中的隐形模块函数

问题描述 投票:0回答:1

我有一个 Hy 模块,看起来像这样:

; a.hy

(defn _add [x y]
  (+ x y))

(defmacro m [x]
  `(_add ~x 2))

我将宏的部分功能导出为模块文件中的常规函数,这是 Hy 手册中提到的良好实践。由于准引用,因此在使用宏时不需要

eval-when-compile
宏即可工作在同一个文件中。但是,我想导出宏,同时对导入它的模块隐藏该函数;这不能按原样工作:

; b.hy

(require a *)

(print (m 5)) ; => NameError: name '_add' is not defined

eval-and-compile
eval-when-compile
都无法解决此问题,并且除了要求模块之外导入模块也不起作用!

; b.hy

(require a *)
(import a *)

(print (m 5)) ; => NameError, still!

我可以让它工作的唯一方法是让宏导入自己的模块以访问

_add

; a.hy

(defn _add [x y]
  (+ x y))

(defmacro m [x]
  `(do (import a [_add])
     (_add ~x 2)))

这是jank,可能不一致(我不知道self-

import
将如何根据项目路径表现,尽管现在我在全局路径中只有
a.hy
)并且not隐藏导入模块的辅助函数:

; b.hy

(require a *)

(print (m 5))      ; => 7
(print (_add 5 2)) ; => 7 (expected NameError)

有更好的方法吗?

module macros hy
1个回答
0
投票

我可以让它工作的唯一方法是让宏导入自己的模块以访问

_add

您所描述的这种方式实际上是正确的做法。只需注意在生成代码中包含导入和在宏代码本身中导入之间的区别即可。这就是

(defmacro m [] (import foo) …)
(defmacro m [] `(do (import foo) …))
之间的区别。另请注意,我在手册中推荐的良好实践是提取生成代码的子例程,而不是在扩展中调用的子例程。

为了避免名称空间污染,请参阅您链接的部分中的这段文字:

您可以使用

import
require
将模块名称或其成员之一绑定到 gensym,但通常更方便的选择是使用一次性导入语法
hy.I
或一次性 require 语法
hy.R

(defmacro hypotenuse [a b]
 `(hy.I.math.sqrt (+ (** ~a 2) (** ~b 2))))
(hypotenuse 3 4)

所以,你会写

(defmacro m [x]
  `(hy.I.a._add ~x 2))
© www.soinside.com 2019 - 2024. All rights reserved.