记事本,口译员和闭包

时间:2011-11-19 10:26:36

标签: programming-languages scheme interpreter memoization

所以我正在尝试,并在计划中创建了一种编程语言。我也为它构建了一个解释器,这是下面的大部分代码。

我想重写解释器,以便在较小的环境中构建闭包,即。在构建闭包时,它使用的环境类似于当前环境,但只保存闭包的函数部分中的自由变量变量。我正在学习记忆,但这很令人困惑。

编辑:我现在正在使用相当于它的球拍,所以如果它更容易,你应该给我建议。

(define-struct var (string)) ;; a variable, e.g., (make-var "foo")
(define-struct int (num)) ;; a constant number, e.g., (make-int 17)
(define-struct add (e1 e2)) ;; add two expressions
(define-struct fun (name formal body)) ;; a recursive 1-argument function
(define-struct closure (fun env)) ;; closures (made at run-time)

(define (envlookup env str)
    (cond [(null? env) (error "unbound variable during evaluation" str)]
        [(equal? (caar env) str) (cdar env)]
        [#t (envlookup (cdr env) str)]))

(define (eval-prog p)
    (letrec
        ([f (lambda (env p)
            (cond [(var? p) (envlookup env (var-string p))]
                    [(int? p) p]
                    [(add? p) (let ([v1 (f env (add-e1 p))]
                                    [v2 (f env (add-e2 p))])
                                        (if (and (int? v1) (int? v2))
                                            (make-int (+ (int-num v1) (int-num v2)))
                                            (error "TTPL addition applied to non-number")))]
                    [(fun? p) (make-closure p env)]
                    [(closure? p) p]
                    [#t (error "bad TTPL expression")]))])
    (f () p)))

3 个答案:

答案 0 :(得分:1)

第一个问题:您的语言中是否存在绑定变异?目前看起来你没有,但也许你正计划添加它。如果你这样做,那么复制绑定会打开一堆新的蠕虫;需要额外的间接。

回答你的问题:是的,你当然可以这样做,大多数语言实现都可以。这与“安全换空间”的属性有关,因此闭包避免保留对可能以其他方式收集的大值的引用。

实现它非常简单:您可能希望通过对程序进行单个静态传递来使用其自由变量来注释每个表达式。在Racket中,我可能会构建一个哈希表,将表达式与其自由变量列表相关联。

对于它的价值,我可以想象通过这样做可能会让你的语言意外变慢的七种方式:)。

答案 1 :(得分:1)

看起来你想要创建类似平面封闭的东西,或者Dybvig称之为“显示封闭”的东西。也就是说,你必须在lambda中递归地找到自由变量,然后创建一个只包含那些自由变量的闭包表示。

例如,

((lambda (x) (lambda (f) (f x))) a)

会创建一个看起来像[code, a]的闭包。

请看看Dybvig的Three Implementation Models for Scheme,第88页。

答案 2 :(得分:0)

如果你不介意阅读一些Haskell,Write Yourself a Scheme in 48 Hours演示了如何创建闭包:当遇到(lambda ...)表达式时,它的闭包只是设置为当前环境(来自的绑定列表)名称到值)。当评估lambda时,它的主体在该闭包的上下文中加上参数绑定来评估 - 当然不是当前环境。

听起来你想要做的就是剔除成为封闭的环境,也许是为了提高效率。为此,您可以在函数中搜索名称,并仅保留那些未出现在参数列表中的名称。但是,这可能过多,因为lambda使用的每个名称 - 除了它的参数 - 都需要出现在闭包中。因此,我建议简单地提及您已经拥有的环境,其中大部分都将被共享。