首页 文章

方案的简单库机制 - 导入实现

提问于
浏览
3

我实施了一个基本方案(想想SICP) . 现在,我想添加一个基本的导入/库功能,但是无法想出办法 . 到目前为止,我认为两种方法都存在同样的障碍 .

在旧的SICP(第一版)书中有一个make-environment / package章节,也讨论了here . 这将返回一个新环境 .

我想打个电话

(import lib)

其中lib提供环境或过程名称和过程列表 . 我的问题是如何使用库提供的过程以编程方式扩展当前环境 . 使用类似的东西

((lambda (name proc) (define name proc)) 'test (lambda a (+ a a)))

由于 define 无法创建超出 lambda 范围的绑定,因此无法正常工作 .

我查看了r6rs的参考实现,但无法弄清楚 import 的底层机制是什么 . 它是如何创建绑定的?

更新1

我认为我的基本问题(问题)是不可能在 lambda 中使用 define ,因为通过 define 完成的环境修改仅限于周围 lambda 的范围 . 有没有为什么programaticaly define 多个(例如生成)程序 .

这有效(类似于所描述的here):

((eval `square-rrot scientific-lib) 4)

还有这个

(eval `(square-rrot 4) scientific-lib)

我甚至可以写

(define sqrt (eval `square-root scientific-lib))

然而,上面的内容是不可持续的,如果我有一个包含100个函数的库,我无法一个一个地定义它们,我需要一个编程方式来做到这一点,但我不能使用类似的东西:

((lambda (newName, libName) (define newName (eval libName scientific-lib))) sqrt `square-root)

在阅读评论和答案之后,在我看来,基于SIPC提供的内容是不可能的 . 一个人需要更高级的东西,如 define-syntax . 或者我错了?

2 回答

  • 1

    因此,您的库只需要成为一组具有本地环境(如定义中)的评估表单 . 库生成的值将是某种对象添加到可用库的全局列表中,这些库具有名称以及要导出的值(过程,语法,...) .

    导入通常具有大量功能,但实际上它只需要一个库对象并将它想要的绑定插入到一个框架中,并将该程序/库的主体放在该框架中 .

    您可以在Scheme中进行粗略的库实现,但只要您不能轻易地更改环境框架,就需要命名您需要导入的内容:

    ;; crude library support made with 
    ;; syntax rules and closures
    #!r6rs
    (import (rnrs base)
            (only (srfi :1) filter any))
    
    (define-syntax lib
      (syntax-rules ()
        ((_ name (export-symbols ...) body ...)
         (define name
           (let ()
             ; make the defines local
             ; here you import other libraries
             body ... 
    
             ;; ^binds is a assoc between symbols and
             ;; implementation. 
             (define ^binds
               (list (cons 'export-symbols export-symbols) ...))
    
             ;; the function to leak definitions
             (lambda args
               (apply values 
                      (map cdr 
                           (filter 
                            (lambda (x)
                              (any (lambda (e)
                                     (eq? e (car x)))
                                   args))
                            ^binds)))))))))
    
    (define-syntax imp
      (syntax-rules ()
        ((_ name sym1)
         (define sym1 (name 'sym1)))
        ((_ name symn ...)
         (begin
           (imp name symn) ...))))
    
    ;; test
    (lib test (add sub)
         (define (add a b)
           (sub a (sub 0 b)))
         (define (sub a b)
           (- a b)))
    
    (imp test add)
    (add 5 3) ; ==> 8
    

    这看起来并不多,但是 add 使用来自同一个库的 sub ,因为我们没有导入它,所以全局不可用 . 你看?你甚至可以拥有私人(非出口)程序 .

    它的主要工作方式是泄漏由库表单创建的闭包部分的过程,它与消息传递背后的想法相同 . (在Scheme中做OOP的一种方法)

  • 0

    这是我最终如何做到的 . 基本上我离开了计划并为lambda添加了一面旗帜 . 然后lambda可以是范围的,也可以不是 . 范围内的lambda表现为通常的lambda . 在lambda没有作用域的情况下,我在空的环境中评估身体 . 然后在当前环境中对其进行评估 . 像这样的东西:

    if (lambdaHasAttribute(lambda, SCOPED)) {
            eenv = environment_extend(parameter, arguments, lambda_env);
            tmp = eval(lambda_body, eenv);
        } else {
            eenv = environment_extend(parameter, arguments, , mk_environment());
            /* scope arguments */
            tmp = eval(lambda_body, eenv);
            /* evaluate unscoped */
            tmp = eval(tmp, global_env);
        }
    

相关问题