我有用 JavaScript 编写的 LISP(https://jcubic.github.io/lips/带有在线演示,您可以在其中尝试)并且我有这样的宏:
(define-macro (globalize symbol)
(let ((obj (--> (. lips 'env) (get symbol))))
`(begin
,@(map (lambda (key)
(print (concat key " " (function? (. obj key))))
(if (function? (. obj key))
(let* ((fname (gensym))
(args (gensym))
(code `(define (,(string->symbol key) . ,args)
(apply (. ,obj ,key) ,args))))
(print code)
code)))
;; native Object.key function call on input object
(array->list (--> Object (keys obj)))))))
在这段代码中,我使用这个:
(let ((obj (--> (. lips 'env) (get symbol))))
我使用以下方法调用此宏:
(globalize pfs)
为 pfs 的每个静态方法创建函数(这是来自 isomorphic-git 的 LightingFS,其中每个函数都返回一个承诺,就像来自节点的 fs)。
但它不适用于这样的事情:
(let ((x pfs))
(globalize x))
因为lips.env 是全局环境。
所以我的问题是宏应该如何工作?他们是否应该只将输入数据作为符号处理,以便在评估 lisp 代码之前永远无法访问对象?
基于变量生成一堆函数的 LISP 宏应该是什么样子。例如,在方案中,如果我在变量中有 alist 并且想要为每个将返回值的键生成函数:
输入:
(define input `((foo . 10) (bar . 20)))
输出:
(begin
(define (foo) 10)
(define (bar) 20))
如果我使用,我可以编写会给出这样输出的宏(macro input)
吗?还是唯一的选择是(macro ((foo . 10) (bar . 20)))
?
我可以接受通用方案或通用 LISP 答案,但请不要从方案中发布定义语法和卫生宏,我的 lisp 没有它们,也永远不会有。
问题似乎是我想在宏扩展时访问值,并且它需要在运行时具有该值。第二个问题eval在这种情况下是唯一的选择吗?
这适用于biwascheme:
(define-macro (macro obj)
(let ((obj (eval obj)))
`(begin
,@(map (lambda (pair)
(let ((name (car pair))
(value (cdr pair)))
`(define (,name) ,value)))
obj))))
(define input `((foo . 10) (bar . 20)))
(macro input)
(foo)
;; ==> 10
(bar)
;; ==> 20
(在我的 lisp eval 中不像在 biwascheme 中那样工作,但这是另一个问题)。
但这不起作用,因为 x 不是全局的:
(let ((x '((g . 10)))) (macro x))
带有 eval 的宏是您通常会做的事情,还是应该避免使用它们?有没有其他方法可以基于运行时对象生成一堆函数。