4

我正在使用 SICP 讲座和文本来自己了解 Scheme。我正在看一个练习,上面写着“表达式 E 的应用程序是 (E E1,...En) 形式的表达式。这包括 n=0 的情况,对应于表达式 (E)。Curried 应用程序E 的应用要么是 E 的应用,要么是 E 的 Curried 应用的应用。”

(编辑:我更正了上面的引用......我最初错误地引用了定义。)

任务是定义计算为 3 的过程的 Curried 应用程序

(define foo1
    (lambda (x)
        (* x x)))

我真的不明白这里的想法,阅读关于 Curriying 的维基百科条目并没有真正帮助。

任何人都可以帮助更清楚地解释这里的要求吗?

实际上,即使给我这个问题的答案也会有所帮助,因为在这个问题之后还有五个要解决。...我只是没有得到基本的想法。

补充:即使在布赖恩坎贝尔冗长的解释之后,我仍然有些迷茫。

(foo1 (sqrt 3)))认为是 foo 的应用程序,因此是 foo 的柯里化应用程序?

看起来太简单了,但也许...

输入(((foo1 2 )) 2)DrScheme 会出现以下错误(我有点预料到)

procedure application: expected procedure, given: 4 (no arguments)

重新阅读什么是柯里化?我知道我也可以将 foo1 重新定义为:

(define (foo1 a)
    (lambda (b)
        (* a b)))

那么我可以输入

((foo1 3 ) 4)

12

但这并没有真正让我更接近于产生 3 作为输出,而且看起来这并不是真正对原始 foo1 进行柯里化,它只是重新定义它。

该死,20 年的 C 编程并没有让我为此做好准备。:-) :-)

4

6 回答 6

7

嗯,与通常更清晰的书籍风格相比,这个问题的措辞相当混乱。实际上,如果您从此处获取问题集,您可能会错误地引用问题集;这可能会导致您的困惑。

我将为您分解定义,并提供一些示例可以帮助您弄清楚发生了什么。

表达式 E 的应用是 (E E1 ... En) 形式的表达式。

这是一个应用程序的示例:

(foo 1 2)      ; This is an application of foo
(bar 1)        ; This is an application of bar

这包括对应于表达式(E)的情况n=0。

(baz)          ; This is an application of baz

E 的 Curried 应用程序要么是 E 的应用程序,要么是 E 的 Curried 应用程序的应用程序............

这是您引用错误的那个;以上是我在网上找到的问题集的定义。

这个定义有两个部分。从第一个开始:

E 的 Curried 应用程序是 E 的应用程序

(foo 1 2)       ; (1) A Curried application of foo, since it is an application of foo
(bar 1)         ; (2) A Curried application of bar, since it is an application of bar
(baz)           ; (3) A Curried application of baz, since it is an application of baz

或 E 的 Curried 应用程序的应用程序

((foo 1 2) 3)   ; (4) A Curried application of foo, since it is an application of (1)
((bar 1))       ; (5) A Curried application of bar, since it is an application of (2)
((baz) 1 2)     ; (6) A Curried application of baz, since it is an application of (3)
(((foo 1 2) 3)) ; A Curried application of foo, since it is an application of (4)
(((bar 1)) 2)   ; A Curried application of bar, since it is an application of (5)
                ; etc...

这是否为您提供了入门所需的帮助?

编辑:是的,(foo1 (sqrt 3))是一个 Curried 应用程序foo1;就是这么简单。这不是一个很好的问题,因为在许多实现中,您实际上会得到 2.9999999999999996 或类似的东西;不可能有一个准确返回 3 的值,除非您的 Scheme 具有某种精确代数数的表示形式。

你的第二个例子确实是一个错误。foo1返回一个整数,该整数无效。只有后面的一些例子,函数的应用程序的递归情况是有效的。看看foo3,例如。

编辑 2:我刚刚签入了 SICP,看起来这里的概念直到第 1.3 节才解释,而这个作业只提到了第 1.1 节。如果您还没有,我建议您尝试通读第 1.3 节。

于 2009-03-29T06:35:47.237 回答
4

请参阅什么是“柯里化”?

Currying 接受一个函数并提供一个接受单个参数的新函数,并返回指定的函数,并将其第一个参数设置为该参数。

于 2009-03-29T07:06:11.893 回答
3

您得到的大多数答案都是“部分评估”的示例。要在 Scheme 中进行真正的柯里化,您需要语法帮助。像这样:

(define-syntax curry
  (syntax-rules ()
    ((_ (a) body ...) 
     (lambda (a) body ...))
    ((_ (a b ...) body ...)
     (lambda (a) (curry (b ...) body ...)))))

然后您将其用作:

> (define adding-n3 (curry (a b c) (+ a b c)))
> (define adding-n2-to-100 (adding-n3 100))
> ((adding-n2-to-100) 1) 10)
111

> (adding-n3 1)
#<procedure>

> ((adding-n3 1) 10)
#<procedure>
于 2014-01-28T20:34:40.757 回答
3

我不认为 James 的 curry 函数是正确的 - 当我在我的方案解释器中尝试它时出现语法错误。

这是我一直使用的“咖喱”的实现:

> (define curry (lambda (f . c) (lambda x (apply f (append c x)))))
> ((curry list 5 4) 3 2)
(5 4 3 2)

请注意,它也适用于对一个函数进行多个参数的柯里化。

还有一个人写了一个宏,让你编写函数,当你用不足的参数调用它们时隐式地为你咖喱:http ://www.engr.uconn.edu/~jeffm/Papers/curry.html

于 2009-06-26T11:20:48.807 回答
2

我觉得你把自己搞糊涂了。Currying 一个函数接受一个 F(a1,a2,...aN) 类型的函数并将其转换为 F(a1),它返回一个接受 a2 的函数,(它返回一个接受 a3 ......等的函数)

因此,如果您有:

(define F (lambda (a b) (+ a b)))
(F 1 2) ;; ==> 3

您可以对它进行 curry 以制作如下所示的内容:

(define F (lambda (a) (lambda (b) (+ a b))))
((F 1) 2) ;; ==> 3

就您的具体问题而言,这似乎很令人困惑。

(foo1 (sqrt 3))

似乎很合适。我建议暂时离开它并阅读更多这本书。


您实际上可以创建一个为您执行简单咖喱的函数:

(define (curry f x) (lambda (y) (apply f (cons x y))))
(curry = 0) ;; a function that returns true if input is zero
于 2009-06-25T15:32:31.147 回答
0

根据您的 Scheme 实现,可能有一些实用程序能够从错误/异常中恢复,例如,在 Chicken Scheme 中,有condition-case.

(condition-case (func)
    ((exn) (print "error")))

我们可以定义一个函数,它接受任意数量的元素的函数并返回 curryed 形式:

(define curry
    (lambda (func . args)
        (condition-case (apply func args)
           ((exn)
               (lambda plus
                   (apply curry func (append args plus)))))]))))

这有点难看,因为如果你一次使用太多参数,你永远不会得到最终结果,但这会将任何函数变成柯里化形式。

于 2013-03-04T17:51:22.983 回答