【问题标题】:Scheme (Pretty Big): Using a list to define arguments方案(相当大):使用列表来定义参数
【发布时间】:2013-02-11 23:42:57
【问题描述】:

所以我是 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 默认情况下会在全局范围内进行计算。

【问题讨论】:

  • 说明书是否规定了您可以使用或不可以使用哪些功能或特殊形式? fn-maker 真的应该是一个函数吗,例如,您可以将它传递给 apply 或 map 吗? (如果后者是真的,我不知道如何在不使用 eval 的情况下做到这一点。)
  • 另外,在另一个问题上也有一些相关的讨论:stackoverflow.com/questions/1894610/…
  • 对于规则,测试程序将调用 (fn-maker fn-spec) 后跟 (whatever-the-name-was some-args) 形式。我们不允许使用 set!和朋友或任何显式循环函数(递归是可以的)。

标签: functional-programming scheme variadic-functions


【解决方案1】:

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

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

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

下面是在提供interaction-environment 时通过eval 注入全局变量的示例

(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。但我认为那里有一个不同的程序可以用来实现这个目标;检查文档。

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

【讨论】:

    【解决方案2】:

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

    附带说明 - 如果fn-spec 参数将接收一个带有新函数名称和主体的 list,那么请确保在调用时只传递一个参数fn-maker,类似这样:

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

    另外,请考虑使用宏而不是普通过程...

    【讨论】:

    • 我正在使用 DrRacket 的 Pretty Big 版本进行此操作,所以它可能就在其中(尚未找到但仍在寻找)。看来我在示例中删除了一个括号,现在已修复。它应该是一个列表。宏似乎是一种非常有用的方法,我仍在弄清楚它们的细节(以前从未听说过它们)但非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 2016-01-09
    • 2013-04-18
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多