这个问题的范围类似于:In R6RS Scheme, is there a way to get the current environment for use with eval?,但我想更进一步,问你如何补救这样的事情。
我的问题进一步混淆,因为在我的情况下'(+ x y)
是一个任意未评估的lambda语句。未评估,因为它可能包含对作为let的一部分的变量的调用(并且由于Scheme不相信在包含这些变量的环境中将调用该过程,而当前的变量没有,它会触发未定义的标识符错误) 。所以问题就变成了:我如何重构我的代码,这样这个范围的噩梦不再是一个问题?每当调用lambda时,我仍然可以使用let中的环境变量。
我正在使用Pretty Big
目的是在Scheme中创建类。到目前为止我的方法相当大(没有双关语意)但看起来像:
(define (dispatch msg methods args)
(if (null? methods) (display "Method signature not found.")
(let (
(m-name (caar methods))
(m-args (cadar methods))
(m-body (caddar methods)))
(if (and (eq? msg (caar methods)) (eq? (length args) (length (cadar methods))))
`(lambda ,m-args ,m-body)
(dispatch msg (cdr methods) args)))))
(define (build-lets c-def)
(let (
(i-vars (cadr c-def))
(meths (caddr c-def)))
(eval `(append ',i-vars (list (list 'methods '',meths))))))
(define (new c-def . args)
(apply (eval `(lambda ,(map cadr (cadr c-def))
(let* ,(build-lets c-def)
(lambda (msg . args)
(letrec ((meth (dispatch msg methods args)))
(apply meth args))))))
args))
其中c-def是形式的类def(比如说一个点)
'(();Name of parent
((yvalue y) (xvalue x)) ;Instance variables: (i-var constructor-arg)
((getx () xvalue) ;Methods, ((name args body) ...)
(setx (x) (set! xvalue x)))))
答案 0 :(得分:3)
这并没有实现您想到的所有语法,但它可能会说明干净地实现它所需的技术。
(define-syntax make-object
(syntax-rules ()
[(__ ([ivar ival] ...) ([method-name args body ...] ...))
(let ([ivar ival] ...)
(λ (msg . oargs)
(cond
[(eq? 'method-name msg)
(apply (λ args body ...) oargs)] ...
[else
(error 'object-system "unknown message" msg)])))]))
(define o (make-object ([xvalue 'x])
([getx () xvalue]
[setx (x) (set! xvalue x)])))
(o 'getx) => x
(o 'setx 'blah)
(o 'getx) => blah
诀窍是编写一个关闭的宏。实例变量位于包含闭包的词法范围(let
)中。关闭是调度员。这些方法是在调度程序中定义的lambdas,因此实例变量与方法在同一范围内。
答案 1 :(得分:0)
如果你可以使let
成为eval的一部分,那么它就可以了。以下是一个例子:
与您的代码类似(但更简单)的东西不起作用:
(define (hello m)
(let ((msg m))
(eval '(print msg))))
让eval的一部分让它起作用:
(define (hello m)
(eval `(let ((msg ,m))
(print msg))))