有很多关于如何理解函数的教程,以及stackoverflow中的许多问题。然而,在阅读了The Little Schemer,几本书,教程,博客文章和stackoverflow主题之后,我仍然不知道这个简单问题的答案:“有什么关系?”我明白如何理解一个功能,而不是“为什么?”背后。
有人可以向我解释一下curried函数的实际用法(除了每个函数只允许一个参数的语言之外,使用currying的必要性当然非常明显。)
编辑:考虑到TLS的一些例子,
的好处是什么?(define (action kind)
(lambda (a b)
(kind a b)))
而不是
(define (action kind a b)
(kind a b))
我只能看到更多代码而没有更多灵活性......
答案 0 :(得分:24)
curried函数的一个有效用途是减少代码量。
考虑三个函数,其中两个几乎完全相同:
(define (add a b)
(action + a b))
(define (mul a b)
(action * a b))
(define (action kind a b)
(kind a b))
如果您的代码调用add
,则代码会action
调用+
种类。与mul
相同。
你定义了这些函数,就像你在许多命令式流行语言中所做的那样(其中一些已经包括lambdas,currying和功能世界中常见的其他功能,因为它们都非常方便)。
所有add
和sum
都会使用相应的action
将呼叫包裹到kind
。现在,考虑这些函数的咖喱定义:
(define add-curried
((curry action) +))
(define mul-curried
((curry action) *))
它们变得相当短。我们只是通过传递一个参数action
来调整函数kind
,并得到了接受其余两个参数的curried函数。
这种方法允许您编写更少的代码,具有高级别的可维护性。
想象一下,函数action
会被立即重写以接受另外3个参数。如果不做好准备,您将不得不重写add
和mul
的实现:
(define (action kind a b c d e)
(kind a b c d e))
(define (add a b c d e)
(action + a b c d e))
(define (mul a b c d e)
(action * a b c d e))
但是,currying使你免于那种令人讨厌且容易出错的工作;您根本不需要在函数add-curried
和mul-curried
中重写符号,因为调用函数将提供传递给action
的必要数量的参数。
答案 1 :(得分:11)
他们可以使代码更容易阅读。考虑以下两个Haskell片段:
lengths :: [[a]] -> [Int]
lengths xs = map length xs
lengths' :: [[a]] -> [Int]
lengths' = map length
为什么要给你不打算使用的变量命名?
Curried函数在以下情况下也有帮助:
doubleAndSum ys = map (\xs -> sum (map (*2) xs) ys
doubleAndSum' = map (sum . map (*2))
删除这些额外的变量会使代码更易于阅读,并且您无需在心理上清楚地了解xs是什么以及是什么。
HTH。
答案 2 :(得分:4)
你可以看到currying是一种专业化。选择一些默认值并让用户(也许是你自己)使用专门的,更具有表现力的功能。
答案 3 :(得分:3)
我认为currying是处理一般n-ary函数的传统方法,只要你能定义的唯一函数是一元的。
例如,在lambda演算中(函数式编程语言源于此),只有一个变量抽象(转换为FPL中的一元函数)。关于lambda演算,我认为更容易证明这种形式主义的事情,因为你实际上并不需要处理n元函数的情况(因为你可以通过currying表示任何n-ary函数与一些一元函数)
(其他人已经介绍了这个决定的一些实际含义,所以我将在这里停止。)
答案 4 :(得分:2)
将all :: (a -> Bool) -> [a] -> Bool
与curried谓词一起使用。
all (`elem` [1,2,3]) [0,3,4,5]
Haskell中缀操作符可以在任何一侧进行curry,因此您可以轻松地对elem
函数(is-element-of)的针或容器侧进行curry。
答案 5 :(得分:2)
我们不能直接编写带有多个参数的函数。由于函数组合是函数式编程中的关键概念之一。通过使用Currying技术,我们可以组成具有多个参数的函数。
答案 6 :(得分:1)
我想在@Francesco回答中添加示例。
答案 7 :(得分:0)
所以你不必用一点lambda来增加样板。
答案 8 :(得分:0)
创建闭包非常容易。我不时使用SRFI-26。真的很可爱。
答案 9 :(得分:0)
本身的currying是语法糖。语法糖就是你想要的容易。例如,C希望在汇编语言中制作“便宜”的指令,如递增,简单,因此它们具有增量的语法糖,++符号。
t = x + y
x = x + 1
替换为t = x ++ + y
功能语言可以很容易地拥有类似的东西。
f(x,y,z) = abc
g(r,s)(z) = f(r,s,z).
h(r)(s)(z) = f(r,s,z)
但是它全部是自动的。并且这允许由特定r0,s0(即特定值)约束的g作为一个变量函数传递。
以perl的排序函数为例 排序子列表 其中sub是两个变量的函数,它们的计算结果为布尔值和 list是一个任意列表。
您自然希望在Perl中使用比较运算符(< =>)并且具有 sortordinal = sort(< =>) sortordinal在列表上工作的地方。要做到这一点,你将成为一个咖喱功能 事实上 在Perl中以这种方式定义了一个列表。
简而言之:currying是糖,使头等功能更自然。