所以我是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使用那些args。就目前而言,lambda创建了一个名为“args”的新局部变量,而不是评估args背后的列表。有没有解决的办法?我目前的思考过程是我应该在args提供的列表中使用某种形式,但我不确定它会是什么样的,甚至不知道如何构建它。
这是作业,所以我绝对不是在寻找代码(欺骗和所有这些),而是在正确的方向和一些批评中找到一点。谢谢。
更新:对于将来发生这种情况的任何人,可以使用一些聪明的引用非常简单地执行此代码。不需要宏。另外,事实证明,Pretty Big中的eval默认情况下会在全局范围内进行评估。
答案 0 :(得分:1)
有一个名为eval
的Scheme过程可用于评估您构造的任意源代码。
通常不鼓励使用它(就像在Javascript和Ruby中一样),因为很多时候使用它,当有更强大的替代品可用时,它被用作不安全的捷径。 (一个简单的例子是当有人可能使用(eval name)
查找与全局环境中的符号相关联的值时,其中name是从一组预定符号中提取的;在这种情况下,构造通常是更好的样式一个单独的查找表,包含所有感兴趣的符号,而不是为此目的破坏全局环境。
无论如何,在一些 Scheme系统中,eval
可用于将新定义注入全局环境。我必须添加限定符“some”,因为在R5RS中,eval
过程同时使用表达式和环境来评估该表达式,并且不需要实现来提供交互式全局环境这个目的。 (即interaction-environment
是可选程序。)
以下是eval
提供时通过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(我认为也是Pretty Big)中,他们没有提供interaction-environment
。但我认为有一个不同的程序可以用来实现这个目标;检查文档。
无论如何,这只是一种尝试在一种策略上提供一个小注释的方式,可能会或可能不会引导您朝着正确的方向前进。强调“可能没有。”
答案 1 :(得分:0)
您需要一种方法来“导出”在过程中创建的函数定义,以使定义存在于全局环境之外。到目前为止,您的实现只会返回lambda
表单。提示:有一种方法可以做到这一点(我记得在Racket中看过它),但它可能是特定于使用的Scheme解释器;我不确定它是否以Pretty Big语言提供。
作为旁注 - 如果fn-spec
参数将接收带有新函数名称和正文的列表,那么请确保只传递一个参数在致电fn-maker
时,会发生以下情况:
(fn-maker '((name: mult5) (x) (* x 5)))
另外,考虑使用宏而不是普通的程序......