12

函数式编程的柯里化与面向对象编程的重载相同吗?如果不是,为什么?(如有可能,请提供示例)

Tks

4

3 回答 3

12

柯里化不是函数式编程特有的,重载也不是面向对象编程特有的。

“柯里化”是使用函数,您可以向其传递比获取剩余参数的函数所需的参数更少的参数。即,如果我们有一个函数plus,它接受两个整数参数并返回它们的总和,那么我们可以将单个参数传递1plus,结果是一个对事物加 1 的函数。

在 Haskellish 语法中(通过邻接函数应用):

plusOne = plusCurried 1
three = plusOne 2
four = plusCurried 2 2
five = plusUncurried 2 3

在模糊的 Cish 语法中(用括号括起来的函数应用程序):

plusOne = plusCurried(1)
three = plusOne(2)
four = plusCurried(2)(2)
five = plusUncurried(2, 3)

您可以在这两个示例中看到plusCurried仅在一个参数上调用,结果是可以绑定到变量然后在另一个参数上调用的结果。您将柯里化视为函数式编程概念的原因是,它在语法通过邻接应用的函数式语言中使用最多,因为在这种语法中柯里化变得非常自然。的应用plusCurriedplusUncurried定义fourfive在 Haskellish 语法中合并变得完全无法区分,因此您可以始终让所有函数完全柯里化(即,让每个函数都是一个参数的函数,只有其中一些会返回其他函数,然后可以将其应用于更多参数)。而在 Cish 语法中,通过括号参数列表应用,four和的定义five看起来完全不同,因此您需要区分plusCurriedplusUncurried。此外,导致今天的面向对象语言的命令式语言从来没有能力将函数绑定到变量或将它们传递给其他函数(这被称为具有一流的函数),没有这种能力,你实际上什么也做不除了在所有参数上调用它之外,还有一个 curried 函数,因此没有任何意义。今天的一些面向对象语言还没有一流的功能,或者是最近才获得的。

currying 一词也指将具有多个参数的函数转换为接受单个参数并返回另一个函数(接受单个参数,并且可能返回另一个函数......)的过程,“uncurrying”可以指到做反向转换的过程。


重载是一个完全不相关的概念。重载一个名称意味着给出具有不同特征(参数类型、参数数量、返回类型等)的多个定义,并让编译器通过它出现的上下文来解析哪个定义是由名称的给定外观表示的。

一个相当明显的例子是,我们可以定义plus添加整数,但也可以使用相同的名称plus添加浮点数,我们可以潜在地使用它来连接字符串、数组、列表等,或者添加向量或矩阵。所有这些都有非常不同的实现,就语言实现而言彼此无关,但我们只是碰巧给它们取了相同的名称。然后编译器负责确定plus stringA stringB应该调用字符串plus(并返回一个字符串),而plus intX intY应该调用整数plus(并返回一个整数)。

同样,这个概念是“OO 概念”而不是函数式编程概念并没有内在的原因。碰巧它很自然地适合已开发的静态类型的面向对象语言。如果您已经在解决调用该方法的对象要调用哪个方法,那么允许更一般的重载只是一个小范围。完全即席重载(您只需多次定义相同的名称并相信编译器会弄清楚)在具有一流函数的语言中不太适合,因为当您将重载名称作为功能本身你不'重载的定义)。Haskell 开发类型类作为使用重载的更原则性方式;这些实际上确实允许您一次传递所有重载定义,并且还允许类型系统表达类型有点像“定义了函数fg定义的任何类型”。


总之:

  • 柯里化和重载完全不相关
  • currying 是关于将函数应用于比它们需要的更少的参数,以便获得剩余参数的函数
  • 重载是为同一名称提供多个定义,并让编译器在每次使用该名称时选择使用哪个定义
  • 柯里化和重载都不是函数式编程或面向对象编程所特有的;由于语言的发展方式,它们都恰好在一种或另一种历史语言中更普遍,导致它们在一种语言中更有用或更明显
于 2012-05-16T07:01:20.130 回答
12

No, they are entirely unrelated and dissimilar.

Overloading is a technique for allowing the same code to be used at different types -- often known in functional programming as polymorphism (of various forms).

A polymorphic function:

 map :: (a -> b) -> [a] -> [b]
 map f []     = []
 map f (x:xs) = f x : map f xs

Here, map is a function that operates on any list. It is polymorphic -- it works just as well with a list of Int as a list of trees of hashtables. It also is higher-order, in that it is a function that takes a function as an argument.

Currying is the transformation of a function that takes a structure of n arguments, into a chain of functions each taking one argument.

In curried languages, you can apply any function to some of its arguments, yielding a function that takes the rest of the arguments. The partially-applied function is a closure.

And you can transform a curried function into an uncurried one (and vice-versa) by applying the transformation invented by Curry and Schonfinkel.

curry :: ((a, b) -> c) -> a -> b -> c 
   -- curry converts an uncurried function to a curried function.

uncurry :: (a -> b -> c) -> (a, b) -> c
   -- uncurry converts a curried function to a function on pairs.
于 2012-05-16T00:44:11.250 回答
2

重载是具有多个具有相同名称的函数,具有不同的参数。

柯里化是您可以获取多个参数并有选择地设置一些参数的地方,例如,您可能只有一个变量。

所以,如果你有一个 3 维的绘图函数,你可能有: justgraphit(double[] x, double[] y, double[] z),并且你想要绘制它。

通过柯里化,您可以: var fx = justgraphit(xlist)(y)(z)您现在设置 fx 的位置,以便它现在有两个变量。

然后,稍后,用户选择另一个轴(日期)并设置 y,所以现在您有: var fy = fx(ylist)(z)

然后,稍后您仅通过循环一些数据来绘制信息,唯一的可变性是z参数。

这使复杂的函数变得更简单,因为您不必继续传递大部分设置的变量,因此可读性增加。

于 2012-05-16T00:51:33.613 回答