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

时间:2014-11-21 17:35:54

标签: scheme sicp

我实施了一个基本方案(想想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

我认为我遇到的基本问题(问题)是在define内使用lambda是不可能的,因为通过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 个答案:

答案 0 :(得分: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,因为我们没有导入它,所以全局无法使用{{1}}。你看?您甚至可以拥有私有(非导出)程序。

它的主要工作方式是泄漏由图书馆表格制作的封闭部分,并且它与消息传递背后的想法相同。 (在方案中做OOP的一种方法)

答案 1 :(得分: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);
    }