什么是F#的currying?

时间:2010-11-08 13:36:53

标签: f# currying

  

可能重复:
  Functional programming: currying

我在这里阅读免费的F#Wikibook:

http://en.wikibooks.org/wiki/F_Sharp_Programming

有一节解释了部分功能是什么。它说使用F#你可以部分使用一个功能,但我无法理解发生了什么。请考虑以下使用示例的代码段:

#light
open System

let addTwoNumbers x y = x + y
let add5ToNumber = addTwoNumbers 5

Console.WriteLine(add5ToNumber 6)

输出是11.但我没有关注。我的函数'add5ToNumber'不会询问一个参数,为什么我可以调用它并给它一个呢?

这些天我真的很喜欢学习F#,宝贝步骤!

5 个答案:

答案 0 :(得分:3)

Currying就是这样的:

addTwoNumbers是一个函数,它接受一个数字并返回一个函数,该函数接受一个返回数字的数字。

所以addTwoNumbers 5实际上是一个函数,它接受一个数字并返回一个数字,这就是curry的工作原理。由于您将addTwoNumbers 5分配给add5ToNumber,因此add5ToNumber使一个带数字的函数返回一个数字。

我不知道F#中的类型定义是什么样的,但在Haskell中,函数的类型定义清楚地说明了这一点:

addTwoNumbers :: (Num a) => a -> a -> a

另一方面,如果你写了addTwonumbers来取两个元组,

addTwoNumbers :: (Num a) => (a, a) -> a

然后是一个需要两个元组并返回一个数字的函数,因此无法创建add5ToNumber

答案 1 :(得分:2)

基本上,F#中的每个函数都有一个参数并返回一个值。该值可以是单位类型,由()指定,在概念上与其他语言中的void类似。

当你有一个似乎有多个参数的函数时,F#将它视为多个函数,每个函数都有一个参数,然后“curry”以得出你想要的结果。所以,在你的例子中,你有:

let addTwoNumbers x y = x + y

这实际上是两个不同的功能。一个需要x并创建一个新函数,它将x的值添加到新函数参数的值中。新函数使用参数y并返回整数结果。

因此,addTwoNumbers 5 6确实会返回11.但是,addTwoNumbers 5在语法上也是有效的,并且会返回一个向其参数添加5的函数。这就是add5ToNumber 6有效的原因。

答案 2 :(得分:1)

只是为了添加其他答案,在引擎盖下方,当你弯曲函数时会返回一个闭包。

[Serializable]
internal class addToFive@12 : FSharpFunc<int, int>
{
    // Fields
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
    public int x;

    // Methods
    internal addToFive@12(int x)
    {
        this.x = x;
    }

    public override int Invoke(int y)
    {
        return Lexer.add(this.x, y);
    }
}

答案 3 :(得分:1)

这被称为 eta-expansion :在函数式语言中,

let f a = g a

相当于

let f = g

这有数学意义:如果两个函数对于每个输入都相等,那么它们是相等的。

在您的示例中,gaddTwoNumbers 5,您编写的代码完全等同于:

let add5toNumber y = addTwoNumbers 5 y

在某些情况下,它们是不同的:

  • 在某些情况下,如果省略它,类型系统可能无法将y识别为普遍量化的。
  • 如果addTwoNumbers 5(仅限一个参数)有副作用(例如向控制台打印5),那么eta扩展版本每次调用时都会打印5,而eta缩减版本会打印当它被定义时。如果addTwoNumbers 5涉及只能进行一次的繁重计算,这也可能会产生性能影响。
  • Eta-reduction对标签和可选参数不是很友好(但它们在F#中不存在,所以没关系)。

当然,除非您的新函数名称具有极高的可读性,否则提供省略参数的名称对读者来说总是有很大的帮助。

答案 4 :(得分:0)

addTwoNumbers接受2个参数(xy)。

仅使用1个参数将

add5ToNumber分配给调用addTwoNumbers的输出,这导致另一个“保存”第一个参数(x -> 5)并接受另一个参数的函数( y)。

当你将6传递给add5ToNumber时,它会将保存的x(5)和给定的y(6)传递给addTwoNumbers,从而产生11