1

所以我是Scheme的新手。我正在尝试使用 ((name: name) (args: args) (body: body)) 形式的规范创建一个定义全局函数的函数,例如

    (fn-maker '((name: mult5) (x) (* x 5)))

会让它变得如此全球化,我可以打电话

    (mult5 3)

并得到 15。

这是我到目前为止所拥有的:

    (define (fn-maker fn-spec)
        (let* (spec (map cdr fn-spec))
              (name (caar spec))
              (args (cadr fn-spec))
              (body (caaddr (cdaddr fn-spec))))
        (lambda (args)
          body)))

我目前主要困惑的是如何让 lambda 使用这些参数。就目前而言,lambda 创建了一个名为“args”的新局部变量,而不是评估 args 后面的列表。有没有解决的办法?我目前的思考过程是,我应该在 args 提供的列表中使用某种形式的 let,但我不确定它会是什么样子,甚至不确定如何构建它。

这是家庭作业,所以我绝对不是在寻找代码(作弊和所有这些),而是寻找正确方向的一点和一些批评。谢谢你。

更新:对于将来发生这种情况的任何人,可以使用一些巧妙的引用非常简单地执行此代码。不需要宏。此外,事实证明,Pretty Big 中的 eval 默认情况下会在全局范围内进行评估。

4

2 回答 2

1

有一个名为 Scheme 的过程eval,可用于评估您构建的任意源代码。

通常不鼓励使用它(就像在JavascriptRuby中一样),因为它被多次使用,当有更强大的替代方案可用时,它被用作不安全的捷径。(一个简单的例子是,有人可能会(eval name)在全局环境中查找与符号关联的值,其中名称是从一组预定的符号中提取的;在这种情况下,构造一个单独的查找表通常是更好的风格所有感兴趣的符号,而不是为此目的颠覆全球环境。

无论如何,在某些Scheme 系统中,eval可用于将新定义注入到全局环境中。我必须添加限定符“some”,因为在R5RS中,该eval过程需要一个表达式和环境来评估该表达式,并且不需要实现为此目的提供交互式全局环境。(即,interaction-environment是一个可选程序。)

下面是通过evalwhen提供的注入全局变量的说明:interaction-environment

(define (make-it-three name) (eval (list 'define name '3) (interaction-environment)))

;; At the REPL now

> (make-it-three 'x)

> x
3

> (map make-it-three '(a b c))
(#!unspecified #!unspecified #!unspecified)

> (+ a b c)
9

Racket(我认为也是相当大)中,他们不提供interaction-environment. 但我认为那里有一个不同的程序可以用来实现这个目标;检查文档。

无论如何,这只是一种尝试对可能会或可能不会将您引向正确方向的策略提供小提示的方式。强调“可能不会”。

于 2013-02-12T02:02:35.547 回答
0

您需要一种方法来“导出”在过程中创建的函数定义,以使该定义存在于全局环境之外。到目前为止,您的实现只会返回一个lambda表单。提示:有一种方法可以做到这一点(我记得在 Racket 中看到过),但它可能特定于使用的 Scheme 解释器;而且我不确定它是否可以在 Pretty Big 语言中使用。

附带说明 - 如果fn-spec参数要接收包含新函数名称和主体的列表,请确保在调用时只传递一个参数fn-maker,如下所示:

(fn-maker '((name: mult5) (x) (* x 5)))

另外,考虑使用宏而不是简单的过程......

于 2013-02-12T00:08:15.650 回答