代码之家  ›  专栏  ›  技术社区  ›  xnv23

使用方案中的变量创建环境

  •  2
  • xnv23  · 技术社区  · 6 年前

    我想创造一些类似于物体或环境的东西 OOP

    这就是我所想的:

    (define env (variable 'x 10 env))
    

    其中,我定义了一个env,并在该环境中创建了一个值为10的变量。

    我还希望能够调用该环境中的值。例如

    (get-value env 'x)
    > 10
    

    我最能理解的是 closures 但我不知道从哪里开始

    2 回复  |  直到 6 年前
        1
  •  2
  •   Sylwester    6 年前

    有很多方法可以做到这一点。这个 classical way 使用列表:

    (define (variable name value env)
      (cons (cons name value) env))
    
    (define (get-value name env)
      (let ((val (assq name env)))
        (if val 
            (cdr val)
            (error "Unbound variable" name)))) ;  for r6rs use raise
    
    ;; the empty environment
    (define the-empty-environment '())
    

    Al Petrofsky制造 eiod (在一个定义中求值)它是这样做的:

    ;; actually called extend
    (define (variable name value env)
      (lambda (i) (if (eq? name i) value (env i)))
    
    ;; just a wrapper, no need for it since you can just call env with the name
    (define (get-value name env)
      (env name))
    
    ;; the empty environment
    (define (the-empty-environment i) 
      (error "Unbound variable" i))
    

    在里面 SICP 您有带绑定的框架:

    ;; actually called extend-environment
    (define (variables vars vals env)
      (if (= (length vars) (length vals))
          (cons (make-frame vars vals) env)
          (if (< (length vars) (length vals))
              (error "Too many arguments supplied" vars vals)
              (error "Too few arguments supplied" vars vals))))
    
    ;; actualy called lookup-variable-value 
    (define (get-value var env)
      (define (env-loop env)
        (define (scan vars vals)
          (cond ((null? vars)
                 (env-loop (enclosing-environment env)))
                ((eq? var (car vars))
                 (car vals))
                (else (scan (cdr vars) (cdr vals)))))
        (if (eq? env the-empty-environment)
            (error "Unbound variable" var)
            (let ((frame (first-frame env)))
              (scan (frame-variables frame)
                    (frame-values frame)))))
      (env-loop env))
    
    
    ;; the empty environment
    (define the-empty-environment '())
    
    ;; referenced
    (define (enclosing-environment env) (cdr env))
    (define (first-frame env) (car env))
    (define (make-frame variables values)
      (cons variables values))
    (define (frame-variables frame) (car frame))
    (define (frame-values frame) (cdr frame))
    

    请注意,与其他添加一个的方法不同,这会添加一个完整的集合。例如绑定 x 5 y 7 您可以:

    (variables '(x y)  '(5 7) env)
    

    我将补充我自己的观点:

    (define (variable var val env)
      (hash-set env var val))
    
    (define (get-value name env)
      (hash-ref env name (lambda () (error "Unbound variable" name))))
    
    ;; the empty environment
    (define the-empty-environment '#hasheq()) 
    

    这个答案的要点是,如果您可以选择 get-value , variable the-empty-environment . 只要您能够实现这些,如何实现其实并不重要。您可以用一个替换另一个,解释器仍然可以工作。这是除了SICP之外的一个要求你一次做一帧的操作。

        2
  •  1
  •   John Clements    6 年前

    实现这一点的最简单方法是使用alist。以上 variable get-value 定义如下:

    (define (variable name value env) (cons (cons name value) env))
    (define (get-value name env) (cond ((assq name env) => cdr) (else #f)))
    

    初始环境为 '() 如果要隐藏空列表,也可以这样定义:

    (define initial-env '())