我有LISP用JavaScript编写(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,其中每个函数返回一个promise,就像来自节点的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答案,但请不要发布方案中的define-syntax和卫生宏,我的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您通常会做什么,还是应该避免?是否有其他方法可以基于运行时对象生成一堆函数。
在Common Lisp中:在运行时创建和编译函数。
CL-USER 20 > (defparameter *input* '((foo . 10) (bar . 20)))
*INPUT*
CL-USER 21 > (defun make-my-functions (input)
(loop for (symbol . number) in input
do (compile symbol `(lambda () ,number))))
MAKE-MY-FUNCTIONS
CL-USER 22 > (make-my-functions *input*)
NIL
CL-USER 23 > (foo)
10
CL-USER 24 > (bar)
20
从局部变量:
CL-USER 25 > (let ((input '((foo2 . 102) (bar3 . 303))))
(make-my-functions input))
NIL
CL-USER 26 > (bar3)
303
使用宏,更笨拙和有限:
CL-USER 37 > (defparameter *input* '((foo1 . 101) (bar2 . 202)))
*INPUT*
CL-USER 38 > (defmacro def-my-functions (input &optional getter)
`(progn
,@(loop for (symbol . number) in (if getter
(funcall getter input)
input)
collect `(defun ,symbol () ,number))))
DEF-MY-FUNCTIONS
CL-USER 39 > (def-my-functions *input* symbol-value)
BAR2
CL-USER 40 > (foo1)
101