我在这里阅读免费的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#,宝贝步骤!
答案 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
这有数学意义:如果两个函数对于每个输入都相等,那么它们是相等的。
在您的示例中,g
为addTwoNumbers 5
,您编写的代码完全等同于:
let add5toNumber y = addTwoNumbers 5 y
在某些情况下,它们是不同的:
y
识别为普遍量化的。 addTwoNumbers 5
(仅限一个参数)有副作用(例如向控制台打印5),那么eta扩展版本每次调用时都会打印5,而eta缩减版本会打印当它被定义时。如果addTwoNumbers 5
涉及只能进行一次的繁重计算,这也可能会产生性能影响。 当然,除非您的新函数名称具有极高的可读性,否则提供省略参数的名称对读者来说总是有很大的帮助。
答案 4 :(得分:0)
addTwoNumbers
接受2个参数(x
和y
)。
add5ToNumber
分配给调用addTwoNumbers
的输出,这导致另一个“保存”第一个参数(x -> 5
)并接受另一个参数的函数( y
)。
当你将6传递给add5ToNumber
时,它会将保存的x
(5)和给定的y
(6)传递给addTwoNumbers
,从而产生11