在lambda表达式中查找自由变量

时间:2012-04-29 00:49:14

标签: functional-programming lisp scheme

有谁知道如何找出lambda表达式中的自由变量?自由变量是不属于lambda参数的变量。

我当前的方法(让我无处可去)就是简单地使用car和cdr来完成表达式。我的主要问题是确定一个值是一个变量还是它是一个scheme原语。有没有办法测试某些内容是否符合方案的内置函数之一?例如:

(is-scheme-primitive? 'and)
;Value: #t

我正在使用麻省理工学院计划。

2 个答案:

答案 0 :(得分:6)

对于任意MIT Scheme程序,没有任何方法可以做到这一点。一个问题是您描述的功能无法正常工作。例如,这不使用'scheme primitive'and

(let ((and 7)) (+ and 1))

但肯定使用符号'and

另一个问题是很多东西,比如and,都是用宏实现的特殊形式。你需要知道你的程序中的所有宏扩展到什么,以找出你的程序中使用的变量。

要使其工作,您需要限制您接受的程序集作为输入。最好的选择是将其限制为“完全扩展”的程序。换句话说,您希望确保在free-variables函数的输入中没有使用任何宏。

为此,您可以使用许多Scheme系统提供的expand功能。不幸的是,从online documentation来看,它看起来不像MIT Scheme提供的这个功能。如果您能够使用其他系统,则Racket会提供expand函数以及local-expand,它可以在宏内正常工作。

实际上,Racket还提供了您要求的free-variables function的实现,正如我所描述的那样,它需要完全扩展的程序作为输入(例如expandlocal-expand的输出)。您也可以看到source code

有关完全扩展源代码所涉问题的详细讨论,请参阅Flatt,Culpepper,Darais和Findler的this upcoming paper

答案 1 :(得分:3)

[编辑4]免责声明;或者,回顾一年后:

这实际上是解决这个问题的一个非常糟糕的方法。它可以作为非常快速而肮脏的方法来实现OP的基本目标,但不能经受任何“现实生活”用例。请参阅本答案评论中的讨论以及其他答案,了解原因。

[/ EDIT]

这个解决方案可能不太理想,但它适用于你想在mit-scheme 的REPL环境中提供的任何lambda形式(参见编辑)。我使用的程序的文档位于the mit.edu doc site. get-vars,引用lambda并返回对列表。每对的第一个元素是符号,第二个元素是environment-reference-type返回的值。

(define (flatten lst)
  (cond ((null? lst) ())
        ((pair? (car lst)) (append (flatten (car lst)) (flatten (cdr lst))))
        (else
          (cons (car lst) (flatten (cdr lst))))))

(define (get-free-vars proc-form)
  (let ((env (ge (eval proc-form user-initial-environment))))
    (let loop ((pf (flatten proc-form))
               (out ()))
      (cond ((null? pf) out)
            ((symbol? (car pf))
             (loop (cdr pf) (cons (cons (car pf) (environment-reference-type env (car pf))) out)))
            (else
              (loop (cdr pf) out))))))

编辑:示例用法:

(define a 100)

(get-vars '(lambda (x) (* x a g)))
 => ((g . unbound) (a . normal) (x . unbound) (* . normal) (x . unbound) (lambda . macro))

编辑2:更改了代码以防止使用符号以外的其他内容调用environment-reference-type

编辑3:正如Sam在评论中指出的那样,这将不会看到在lambda下的let中绑定的符号具有任何值..不确定是否有一个简单的解决方案。所以,我关于这个问题的陈述是错误的,并且应该更像是“任何不包含新约束形式的简单lambda”......好吧。