如何解决如何创建一个 lambda 程序?
我需要使用 Scheme 完成大学课程的作业。我以前从未在 Scheme 中编码过,所以我不知道我在做什么。我们的任务是定义一个匿名函数来计算二次函数的判别式。我不断遇到错误:“无效的‘定义’。任何帮助将不胜感激。
(define roots (lambda(abc))(
(lambda(discriminant))(
list(/(+(-b) discriminant)(*2a))
(/(-(-b) discriminant)(*2a))
)
(sqrt - (*bb)(*4ac))
)
解决方法
首先,你应该了解一下 Scheme 代码是什么样的;找到一些示例代码(在您的教科书中,或在线,或在 SO 上的答案中)并注意括号和空格的使用方式。然后效仿。您不能在 Scheme(或任何 Lisp)中任意放置括号或任意删除空格。
例如,在发布的代码中 (-b)
有两处错误。首先,-b
被视为一个符号,而不是 b
值的否定。此外,将符号放在括号中表示过程调用;给定一个 s 表达式 (f x)
,f
要么是句法关键字(在这种情况下 (f x)
被解释为宏调用),或者 (f x)
被解释为过程调用.如果是过程调用并且 f
未绑定到过程,则会引发异常。因此,(-b)
尝试调用一个名为 -b
的过程,该过程不存在(除非您已定义它),从而引发异常。您可以使用 (- b)
,在 -
过程和符号 b
之间有一个空格;这评估为 b
值的否定。
同样,*2a
被解释为一个符号,而不是一个表达式;将 *2a
放在括号之间被解释为过程调用。解释器(或编译器)期望 *2a
是一个不带参数的过程。您需要添加空格:(* 2 a)
;这被解释为使用参数 *
和 2
调用过程 a
。
(*bb)
和 (*4ac)
有完全相同的问题。第二种情况很有趣,因为当它正确编写时,它说明了前缀表示法的优点之一。由于 *
是关联的,因此多个值相乘的顺序无关紧要。要在前缀符号中天真地表达 4 * a * c
,您可以编写 (* 4 (* a c))
,显式地对乘法进行排序。您也可以将其写为 (* (* 4 a) c)
,以不同的顺序相乘。乘以什么顺序无关紧要,因此您不妨直接写成 (* 4 a c)
,只要您的语言支持这种表示法即可。事实证明,Scheme 和其他 Lisp 确实支持这种表示法。
已发布代码中 s 表达式符号的另一个问题(在解决上述问题后):(sqrt - (* b b) (* 4 a c))
。这试图在参数 sqrt
、-
和 (* b b)
上调用 (* 4 a c)
过程。但是 sqrt
不是一个高阶过程(即它不接受过程作为参数),它实际上只接受一个参数。它旨在将 -
过程应用于参数 (* b b)
和 (* 4 a c)
,在取平方根之前减去它们:(sqrt (- (* b b) (* 4 a c)))
。
第一个 lambda
表达式有一个形参列表,只包含一个参数:abc
。和以前一样,这是一个错误。目的是定义三个参数:不要吝啬空格:(lambda (a b c))
。
另一个重要问题是 lambda
表达式中存在语法错误:(lambda (a b c))
没有正文,但 lambda
表达式必须至少有身体里的一种表情。这可能是为了包装后面的 lambda
表达式。类似地,内部 lambda
表达式缺少其主体。它可能是为了包装后面的 (list ;;...)
形式。
完成后,内部 lambda
表达式本身位于一对括号内,将表达式 (sqrt (- (* b b) (* 4 a c)))
作为其参数。这是 lambda
绑定的 let
形式。因此,内部 lambda
接受一个参数 discriminant
,并评估作为其主体的 list
形式。由于内部 lambda
表达式本身出现在 s 表达式的第一个位置,因此它是过程调用的一部分,然后根据其参数调用此内部匿名过程,将 discriminant
绑定到值通过评估该参数获得,即 (sqrt (- (* b b) (* 4 a c)))
。这一切都发生在外部 lambda
内部,它采用三个参数 a
、b
和 c
。因此,root
是一个函数,它带有三个参数,并在将判别计算的结果绑定到 discriminant
之后返回一个根列表(作为一种既简化根的表达式又确保判别式只需要计算一次)
这是修复代码。请注意,我只添加了一些空格并添加或移动了一些括号;没有其他任何改变:
(define roots
(lambda (a b c)
((lambda (discriminant)
(list (/ (+ (- b) discriminant) (* 2 a))
(/ (- (- b) discriminant) (* 2 a))))
(sqrt (- (* b b) (* 4 a c))))))
注意这看起来像什么。在 Lisps 中,您几乎不应该将括号单独放在一行上,并且您应该始终在参数之间放置一个空格。请记住,一切都是过程调用。
这是一个示例交互。请注意,您可以将负数表示为 -1
而不是 (- 1)
(如果您愿意,您可以使用任何一种)。您只是无法使用变量表示负值作为 -b
。
> (roots 1 0 -1)
(1 -1)
> (roots 1 8 15)
(-3 -5)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。