和重载一样currying吗?

问题描述 投票:9回答:3

函数式编程与OO编程的重载相同吗?如果没有,为什么? (如果可能,请举例)

TKS

oop functional-programming overloading currying
3个回答
11
投票

Currying并非特定于函数式编程,而且重载并非特定于面向对象的编程。

“Currying”是使用函数,您可以传递少于获取其余参数的函数所需的参数。即如果我们有一个函数plus,它接受两个整数参数并返回它们的和,那么我们可以将单个参数1传递给plus,结果是一个向事物添加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)

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

currying一词也指将多个参数的函数转换为一个参数并且返回另一个函数(它接受一个参数,并且可能返回另一个函数......)的过程,并且“uncurrying”可以引用进行逆向转换的过程。


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

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

同样,没有固有的理由说明为什么这个概念是“OO概念”而不是函数式编程概念。它恰好发生在非常自然地适用于开发的静态类型的面向对象语言中;如果你已经解决了调用该方法的对象调用哪个方法,那么它是一个小的延伸,允许更一般的重载。完全临时重载(除了多次定义相同的名称并且信任编译器来解决它)之外什么都不适合用于具有一等函数的语言,因为当你将重载的名称作为一个传递时函数本身你没有调用上下文来帮助你找出预期的定义(如果他们真正想要的是通过所有重载的定义,程序员可能会感到困惑)。 Haskell开发了类型类作为使用重载的更有原则的方式;这些有效地允许您一次传递所有重载的定义,并且还允许类型系统表达类似“任何类型,其中函数fg被定义”。


综上所述:

  • 蜷缩和超载是完全无关的
  • currying是关于将函数应用于少于它们所需的参数以获得剩余参数的函数
  • 重载是为同一个名称提供多个定义,并让编译器选择每次使用名称时使用的定义
  • currying和overloading都不是特定于函数式编程或面向对象的编程;由于语言的发展方式,它们各自恰好在某种历史语言中更为普遍,使它们在一种语言中更有用或更明显

12
投票

不,他们是完全不相关和不相似的。

Overloading是一种允许在不同类型中使用相同代码的技术 - 在函数式编程中通常称为多态(各种形式)。

多态函数:

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

在这里,map是一个可以在任何列表上运行的函数。它是多态的 - 它与Int列表一样可以作为哈希表树的列表。它也是高阶的,因为它是一个以函数作为参数的函数。

Currying是一个函数的转换,它将一个n个参数的结构转换为一个函数链,每个函数都取一个参数。

在curried语言中,您可以将任何函数应用于其某些参数,从而产生一个接受其余参数的函数。部分应用的函数是闭包。

你可以通过应用CurrySchonfinkel发明的转换,将一个curried函数转换为一个未经证实的函数(反之亦然)。

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.

2
投票

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

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

因此,如果你有3个维度的图形函数,你可能有:justgraphit(double[] x, double[] y, double[] z),你想要绘制图形。

通过curry你可以:var fx = justgraphit(xlist)(y)(z)你现在已经设置了fx,所以它现在有两个变量。

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

然后,稍后通过循环一些数据来绘制信息的图形,唯一的变化是z参数。

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

© www.soinside.com 2019 - 2024. All rights reserved.