我实施了一个基本方案(想想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
。或者我错了吗?
答案 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);
}