Macros 运行时处理内部变量和数据结构的LISP宏
我用JavaScript编写了LISP(带有在线演示,您可以在其中试用),我有如下宏:Macros 运行时处理内部变量和数据结构的LISP宏,macros,scheme,lisp,common-lisp,lisp-macros,Macros,Scheme,Lisp,Common Lisp,Lisp Macros,我用JavaScript编写了LISP(带有在线演示,您可以在其中试用),我有如下宏: (define-macro (globalize symbol) (let ((obj (--> (. lips 'env) (get symbol)))) `(begin ,@(map (lambda (key) (print (concat key " " (function? (. obj key)))) (
(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 ((x pfs))
(globalize x))
在这段代码中,我使用:
(let ((obj (--> (. lips 'env) (get symbol))))
我使用以下方法调用此宏:
(globalize pfs)
为pfs的每个静态方法创建函数(这是来自同构git的LightingFS,其中每个函数返回一个承诺,就像来自node的fs)
但它对这样的事情不起作用:
(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 ((x pfs))
(globalize x))
因为lips.env是全球环境
所以我的问题是,宏应该如何工作?他们是否应该只将输入数据作为符号进行处理,以便在对lisp代码求值之前永远无法访问对象
基于变量生成一系列函数的LISP宏应该是什么样子的。例如,在scheme中,如果我在变量中有alist,并希望为每个键生成函数,该函数将返回一个值:
输入:
(define input `((foo . 10) (bar . 20)))
输出:
(begin
(define (foo) 10)
(define (bar) 20))
如果我使用(宏输入)
,是否可以编写将给出此类输出的宏?或者唯一的选项是(宏((foo.10)(bar.20))
我可以接受genericscheme或commonlisp答案,但请不要从Scheme发布定义语法和宏,我的LISP没有它们,也永远不会有
问题似乎是,我希望在宏扩展时访问值,并且它需要具有运行时的值。第二个问题是,在这种情况下,评估是唯一的选择吗
这在以下方面起作用:
(在我的lisp评估中,我的工作不像biwascheme,但这是另一个问题)
但这不起作用,因为x不是全局的:
(let ((x '((g . 10)))) (macro x))
带eval的宏是您通常会做的,还是应该避免?是否有其他方法可以基于运行时对象生成一组函数。在公共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
在公共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
“(..)宏应该如何工作?他们是否应该只将输入数据作为符号处理,以便在对lisp代码求值之前永远无法访问对象?”-是(IMHO)@rsm那么我应该如何在运行时进行操作并创建函数?
(宏x)
将在知道符号x
的意义之前对其进行处理。有些实现在执行之前进行宏扩展,并且在运行时根本没有宏。当eval
可选时,这些系统可以是R5R。扩展应该可以放入(宏x)
位置,并且可以互换工作。如果宏在宏扩展时需要一个值,那么它需要从某处获取该值。这是没有办法的。宏是如何得到它的,可以通过EVAL,向符号询问它的值,从一些数据结构中检索它,等等。所有这些都有一个共同点:这些值需要在宏扩展时检索。”(……)宏应该如何工作?它们应该只将输入数据作为符号进行处理,以便在计算lisp代码之前永远不能访问对象吗?”-是(IMHO)@rsm那么我应该如何在运行时创建函数呢?(宏x)
将在知道符号x
的意义之前对其进行处理。有些实现在执行之前进行宏扩展,并且在运行时根本没有宏。当eval
可选时,这些系统可以是R5R。扩展应该可以放入(宏x)
位置,并且可以互换工作。如果宏在宏扩展时需要一个值,那么它需要从某处获取该值。这是没有办法的。宏是如何得到它的,可以通过EVAL,询问一个符号的值,从一些数据结构中检索它,等等。所有这些都有一个共同点:这些值需要在宏扩展时检索。这适用于简单的情况,但似乎我的简单情况不等于复杂的情况。在我的原始代码中,我有一个可以在运行时获得的名称列表,以及我调用它的对象。不确定,但这就像传递CLOS对象和泛型函数列表,函数或宏生成新的普通函数,其中泛型在其中,它调用该CLOS对象。对象可以在let
@jcubic中:也许您应该解释一下您真正想要做什么。当我们不知道它做什么或应该做什么时,仅仅用您自己的Lisp方言发布代码可能没有多大帮助。@jcubic:正如我在我的示例中所示,Common Lisp可以生成代码并编译它,而无需宏,无论它调用什么和参数是什么。基本规则:如果你想在运行时做一些事情,基于运行时数据,使用一个函数。所以我需要的是像合并两个看起来不兼容的概念闭包和宏扩展之类的东西,或者一种方法<代码>(让((x)(名称“foo”)”(定义(,名称)x))在定义之前有反勾号。所以我需要的是运行时的函数名和闭包中的值。也许我需要不同的定义函数,当在let中使用generete新函数时。在scheme中,这不起作用(至少在biwascheme中),您需要(定义foo(let((x10))(lambda()x))
@jcubic:在方案一中,我会使用一个普通的EVAL,而不是CL的COMPILE。也许一个特定的方案实现也有类似的方法。这适用于简单的情况,但似乎我的简单情况不等于复杂的情况。在我的原始代码中,我有一个可以在运行时获得的名称列表,我调用它的对象。不确定,但这是正确的比如传递CLOS对象和泛型函数列表,函数或宏生成新的普通函数,其中泛型在其中,它调用该CLOS对象。对象可以在let
@jcubic中:也许你应该解释你真正想要做什么。当我们不知道时,仅仅用你自己的Lisp方言发布代码可能没有多大帮助“我不知道它做什么或应该做什么。@jcubic: