在 Scheme 的 lambda 中使用 let 变量 [英] Using let variables in a lambda in Scheme

查看:56
本文介绍了在 Scheme 的 lambda 中使用 let 变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题的范围类似于:在 R6RS Scheme 中,有没有办法让当前环境与 eval 一起使用? 但我想更进一步,问你如何解决这样的问题.

This question is similar in scope to: In R6RS Scheme, is there a way to get the current environment for use with eval? but I'd like to take it a step further and ask how you'd remedy something like this.

我的问题更令人困惑,因为在我的情况下 '(+ x y) 是一个任意的未评估的 lambda 语句.未评估,因为它可能包含对属于 let 一部分的变量的调用(并且由于 Scheme 不相信该过程将在包含这些变量的环境中被调用,而当前的环境不包含这些变量,它会触发未定义的标识符错误).所以问题变成了:我怎样才能重构我的代码,这样范围界定的噩梦不再是一个问题?每当调用 lambda 时,我仍然希望能够使用来自 let 的环境变量.

My issue is further confounded in that in my case '(+ x y) is an arbitrary unevaluated lambda statement. Unevaluated because it may contain calls to variables that are part of the let (and since Scheme doesn't have faith that the procedure will be called in an environment containing those variables when the current one does not, it fires off an undefined identifier error). So the question becomes: how can I restructure my code, such that this scoping nightmare is no longer an issue? I'd like to still be able to use the environment variables from the let whenever the lambda is called.

我正在使用 Pretty Big

目的是在 Scheme 中创建类.到目前为止,我的方法相当大(没有双关语),但看起来像:

The intent is to create classes in Scheme. My approach so far is pretty big (no pun intended) but looks like:

    (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(比如一个点)

Where c-def is a class def of the form (say for a point)

    '(();Name of parent
      ((yvalue y) (xvalue x)) ;Instance variables: (i-var constructor-arg)
      ((getx () xvalue) ;Methods, ((name args body) ...)
       (setx (x) (set! xvalue x)))))

推荐答案

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

This doesn't implement all the syntax you have in mind, but it might illustrate the techniques needed to implement it cleanly.

(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,因此实例变量与方法在同一范围内.

The trick is to write a macro that makes a closure. The instance variables go in a lexical scope (the let) that holds the closure. The closure is the dispatcher. The methods are lambdas defined within the dispatcher, so the instance variables are within the same scope as the methods.

这篇关于在 Scheme 的 lambda 中使用 let 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆