问题 什么是currying的真实用例?


我一直在阅读很多关于currying的文章,但几乎所有这些都是误导性的,将currying解释为部分函数应用程序,并且所有示例通常都是关于arity为2的函数,如 add 功能什么的。

还有很多实现 curry JavaScript中的函数使得每个部分应用程序接受多于1个参数(请参阅 lodash), 什么时候 维基百科文章 清楚地告诉我们说:

将带有多个参数(或参数元组)的函数的求值转换为评估函数序列,每个函数都有一个参数(部分应用程序)

所以基本上currying是一系列部分应用程序,每个应用程序都有一个参数。而且我真的想知道任何语言的真实用途。


8789
2017-09-23 18:53


起源

是什么让你认为这个术语的其他用法是“错误的”? - dfeuer


答案:


currying的实际用例是部分应用。

单独卷曲并不是非常有趣。有趣的是,如果您的编程语言默认支持currying,就像在F#或Haskell中那样。

您可以使用任何支持一流函数的语言定义更高阶函数以进行currying和部分应用,但是当您获得的每个函数都是curry时,它与您获得的灵活性相差甚远,因此无需您执行任何操作即可部分应用。

因此,如果你看到人们将currying和部分应用混为一谈,那是因为这些概念在那里紧密相关 - 因为currying无处不在,你并不需要其他形式的部分应用,而不是将curried函数应用于连续的参数。


7
2017-09-23 20:17



作为一个处于OP职位并且最近看到了currying的吸引力的人,我完全同意这个答案。看完之后 drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html 和 ramdajs.com/0.17/docs/#curry ,事情有意义!这一切都是关于默认情况下将每个函数都设置为curry,这为在代码中使用部分应用的函数作为“构建块”打开了大门。 - TW80000


传递上下文很有用。

考虑'map'功能。它需要一个函数作为参数:

map : (a -> b) -> [a] -> [b]

给定一个使用某种形式的上下文的函数:

f    : SomeContext -> a -> b

这意味着您可以优雅地使用map函数,而无需声明'a'参数:

map (f actualContext) [1,2,3]

没有currying,你将不得不使用lambda:

map (\a -> f actualContext a) [1,2,3]

笔记:

map 是一个函数,它采用包含值的列表 a,一个功能 f。它通过采用每个列表构建一个新列表 a 并申请 f 它,导致一个列表 b

例如 map (+1) [1,2,3] = [2,3,4]


5
2017-09-23 20:28





轴承currying上的代码可以分为两组问题(我用Haskell来说明)。 句法,实现。

语法问题1:

在某些情况下,Currying可以提高代码清晰度。 清晰度意味着什么?读取该功能可清楚地显示其功能。 例如地图功能。

map : (a -> b) -> ([a] -> [b])

以这种方式阅读,我们看到map是一个提升函数转换的高阶函数 as 至 bs 到一个转换的功能 [a] 至 [b]

在理解这些表达时,这种直觉特别有用。

map (map (+1))

内部地图具有上述类型 [a] -> [b]。 为了弄清楚外部地图的类型,我们从上面递归地应用了我们的直觉。因此外部地图升起 [a] -> [b] 至 [[a]] -> [[b]]

这种直觉将带给你很多。 一旦我们推广 map 进入 fmap, 一个 map 在任意容器上,读取这样的表达式变得非常容易(注意我已经对每个表达式进行了单变化 fmap 为了这个例子,为了一个不同的类型)。

showInt : Int -> String
(fmap . fmap . fmap) showInt : Tree (Set [Int]) -> Tree (Set [String])

希望上面说明了这一点 fmap 提供了将香草函数提升到某个任意容器上的函数的概括概念。

语法问题2:

Currying还允许我们以无点形式表达函数。

nthSmallest : Int -> [Int] -> Maybe Int
nthSmallest n = safeHead . drop n . sort

safeHead (x:_) = Just x
safeHead _     = Nothing

上面通常被认为是好的风格,因为它说明了根据功能管道而不是显式操纵数据的思考。

履行

在Haskell中,点自由风格(通过currying)可以帮助我们优化功能。以点自由形式编写函数将允许我们记住它。

memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)


not_memoized_fib  :: Int -> Integer
not_memoized_fib x = map fib [0 ..] !! x
    where fib 0 = 0
          fib 1 = 1
          fib n = not_memoized_fib (n-2) + not_memoized_fib (n-1)

将其写为curoized函数,如memoized版本,将curried函数视为实体,因此将其记忆。


1
2017-09-24 01:25