有谁知道如何找出lambda表达式中的自由变量?自由变量是不属于lambda参数的变量。
我当前的方法(让我无处可去)就是简单地使用car和cdr来完成表达式。我的主要问题是确定一个值是一个变量还是它是一个scheme原语。有没有办法测试某些内容是否符合方案的内置函数之一?例如:
(is-scheme-primitive? 'and)
;Value: #t
我正在使用麻省理工学院计划。
答案 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的实现,正如我所描述的那样,它需要完全扩展的程序作为输入(例如expand
或local-expand
的输出)。您也可以看到source code。
有关完全扩展源代码所涉问题的详细讨论,请参阅Flatt,Culpepper,Darais和Findler的this upcoming paper。
答案 1 :(得分:3)
这实际上是解决这个问题的一个非常糟糕的方法。它可以作为非常快速而肮脏的方法来实现OP的基本目标,但不能经受任何“现实生活”用例。请参阅本答案评论中的讨论以及其他答案,了解原因。
这个解决方案可能不太理想,但它适用于你想在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
”......好吧。