【问题标题】:Using let variables in a lambda in Scheme在 Scheme 的 lambda 中使用 let 变量
【发布时间】:2013-04-17 04:30:28
【问题描述】:

此问题的范围类似于: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)))))

【问题讨论】:

  • 我不确定你要做什么,你有一些示例代码吗?
  • @ChrisJester-Young 我想他想找到一种方法,让(let ((x 1)) (eval '(* x 2))) 之类的东西返回2
  • @Maxwell 完全正确
  • @Maxwell 可以使用 Guile 的 local-eval 处理特定情况,但这不是 Racket 支持的任何内容。因此,我将查看 OP 的更新问题,看看是否有不同的解决方法。
  • @KPatnode 对于您的特定用例,我认为您将不得不使用宏(而不是eval)。当然,Racket 的内置类都是使用宏完成的。

标签: scope scheme


【解决方案1】:

这并没有实现您想到的所有语法,但它可能说明了干净地实现它所需的技术。

(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)。闭包是调度程序。方法是在调度程序中定义的 lambda,因此实例变量与方法在同一范围内。

【讨论】:

  • 这正是我需要让我朝着正确的方向前进。谢谢!
【解决方案2】:

如果您可以将let 作为评估的一部分,那么它将起作用。下面是一个例子:

与您的代码类似(但更简单)但不起作用的代码:

(define (hello m)
  (let ((msg m))
    (eval '(print msg))))

让 eval 的一部分让它工作:

(define (hello m)
  (eval `(let ((msg ,m))
           (print msg))))

【讨论】:

    猜你喜欢
    • 2015-08-09
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多