初学者:Scheme中的Curried函数

时间:2009-03-29 05:37:21

标签: scheme currying

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

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

任务是定义一个Curried应用程序,该程序的计算结果为3

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

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

任何人都可以帮助更明确地解释这里要求的内容吗?

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

补充:即使在Brian Campbell冗长的解释之后,我仍然有点失落。

(foo1 (sqrt 3)))是否被视为foo的应用程序,因此是foo的curry应用程序?

似乎太简单了,但也许......

在DrScheme中键入(((foo1 2 )) 2)会出现以下错误(我有点期待)

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

重新阅读What is Currying?后,我明白我也可以将foo1重新定义为:

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

然后我可以输入

((foo1 3 ) 4)
  

12

但是这并不能让我更接近于将3作为输出,而且看起来这并不是真正的原始foo1,它只是重新定义它。

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

6 个答案:

答案 0 :(得分:7)

嗯,与通常更清晰的书籍风格相比,这个问题相当混乱。实际上,如果您从here获得问题集,看起来您可能会错误地设置问题集;这可能会导致你的困惑。

我会为你打破这个定义,有一些例子可以帮助你弄清楚发生了什么。

  

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

以下是应用程序的示例:

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

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

(baz)          ; This is an application of baz
  

E的Curried申请是E的申请或E Cur的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
  

或者Cur的应用程序的应用

((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))foo1的Curried应用程序;就这么简单。这不是一个非常好的问题,因为在许多实现中你实际上会得到2.9999999999999996或类似的东西;除非您的Scheme有某种精确algebraic numbers的表示,否则不可能有一个将返回3的值。

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

编辑2 :我刚刚检查了SICP,看起来这里的概念直到1.3节才解释,而这个分配只提到了1.1节。如果你还没有,我建议你仔细阅读1.3节。

答案 1 :(得分:3)

请参阅What is 'Currying'?

  

Currying需要一个功能并提供   接受单一的新功能   参数,并返回指定的   函数及其第一个参数集   那个论点。

答案 2 :(得分:3)

我不认为詹姆斯的咖喱功能是正确的 - 当我在我的方案解释器中尝试它时会出现语法错误。

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

> (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

答案 3 :(得分:3)

您获得的大部分答案都是“部分评估”的例子。要在Scheme中进行真正的currying,你需要语法帮助。像这样:

(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>

答案 4 :(得分:2)

我觉得你太困惑了。卷曲函数需要F(a1,a2,... aN)类型的函数并将其转换为F(a1),它返回一个取a2的函数(返回一个取a3 ...等的函数)< / p>

所以如果你有:

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

你可以用它来制作类似如下的东西:

(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

答案 5 :(得分: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)))))]))))

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