F# 中什么是柯里化?
可能的重复:
函数式编程:柯里化
我正在这里阅读免费的 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#,一步一步!
Possible Duplicate:
Functional programming: currying
I'm reading the free F# Wikibook here:
http://en.wikibooks.org/wiki/F_Sharp_Programming
There's a section explaining what Partial Functions are. It says that using F# you can partially use a function, but I just can't understand what's going on. Consider the following code snippet that is used an example:
#light
open System
let addTwoNumbers x y = x + y
let add5ToNumber = addTwoNumbers 5
Console.WriteLine(add5ToNumber 6)
The ouput is 11. But I'm not following. My function 'add5ToNumber' doesn't ask for a paramter so why can I invoke it and give it it one?
I really like learning about F# these days, baby steps!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
基本上,F# 中的每个函数都有一个参数并返回一个值。该值可以是单位类型,由 () 指定,其概念与其他语言中的 void 类似。
当您的函数似乎具有多个参数时,F# 会将其视为多个函数,每个函数都有一个参数,然后对这些函数进行“柯里化”以得出您想要的结果。因此,在您的示例中,您有:
这实际上是两个不同的函数。我们采用
x
并创建一个新函数,该函数会将x
的值添加到新函数参数的值中。新函数采用参数 y 并返回整数结果。因此,addTwoNumbers 5 6 确实会返回 11。但是,addTwoNumbers 5 在语法上也是有效的,并且会返回一个将 5 添加到其参数的函数。这就是
add5ToNumber 6
有效的原因。Basically, every function in F# has one parameter and returns one value. That value can be of type unit, designated by (), which is similar in concept to void in some other languages.
When you have a function that appears to have more than one parameter, F# treats it as several functions, each with one parameter, that are then "curried" to come up with the result you want. So, in your example, you have:
That is really two different functions. One takes
x
and creates a new function that will add the value ofx
to the value of the new function's parameter. The new function takes the parametery
and returns an integer result.So,
addTwoNumbers 5 6
would indeed return 11. But,addTwoNumbers 5
is also syntactically valid and would return a function that adds 5 to its parameter. That is whyadd5ToNumber 6
is valid.柯里化是这样的:
addTwoNumbers 是一个函数,它接受一个数字并返回一个接受一个数字并返回一个数字的函数。
所以
addTwoNumbers 5
实际上是一个接受一个数字并返回一个数字的函数,这就是柯里化的工作原理。由于您将addTwoNumbers 5
分配给add5ToNumber
,这使得add5ToNumber
成为一个接受数字并返回数字的函数。我不知道 F# 中的类型定义是什么样的,但在 Haskell 中,函数的类型定义清楚地说明了这一点:
另一方面,如果您编写
addTwonumbers
来获取两个元组,那么就会是一个接受两个元组并返回一个数字的函数,因此
add5ToNumber
将无法按照您的方式创建。Currying is something like this:
addTwoNumbers
is a function that takes a number and returns a function that takes a number that returns a number.So
addTwoNumbers 5
is in fact a function that takes a number and returns a number, which is how currying works. Since you assignaddTwoNumbers 5
toadd5ToNumber
, that makeadd5ToNumber
a function that takes a number an returns a number.I don't know what type definition looks like in F# but in Haskell, the type definition of functions makes this clear:
On the other hand, if you wrote
addTwonumbers
to take a two tuple,then is would be a function that takes a two tuple and returns a number, so
add5ToNumber
would not be able to be created as you have it.只是为了添加其他答案,当您柯里化该函数时,在幕后会返回一个闭包。
Just to add to the other answers, underneath the hood a closure is returned when you curry the function.
这被称为eta-expansion:在函数式语言中,
相当于
这具有数学意义:如果两个函数对于每个输入都相等,那么它们就相等。
在您的示例中,
g
是addTwoNumbers 5
并且您编写的代码完全等同于:在某些情况下它们是不同的:
y
,则不会将其识别为通用量化的。addTwoNumbers 5
(仅带有一个参数)有副作用(例如将 5 打印到控制台),则 eta 扩展版本将在每次调用时打印 5,而 eta 缩减版本则将定义后打印它。如果addTwoNumbers 5
涉及只能执行一次的繁重计算,这也可能会对性能产生影响。当然,除非您的新函数名称非常易读,否则提供省略的参数的名称始终对读者有很大帮助。
This is known as eta-expansion : in a functional language,
Is equivalent to
This makes mathematical sense : if the two functions are equal for every input, then they're equal.
In your example,
g
isaddTwoNumbers 5
and the code you wrote is entirely equivalent to:There are a few situations where they are different:
y
as universally quantified if you omit it.addTwoNumbers 5
(with one parameter only) has a side-effect (such as printing 5 to the console) then the eta-expanded version would print 5 every time it's called while the eta-reduced version would print it when it's defined. This may also have performance consequences, ifaddTwoNumbers 5
involved heavy calculations that can be done only once.And, of course, unless your new function name is extremely readable, providing the names of the omitted arguments is always a great help for the reader.
addTwoNumbers
接受 2 个参数(x
和y
)。add5ToNumber
被分配给仅使用 1 个参数调用addTwoNumbers
的输出,这会导致另一个函数“保存”第一个参数 (x -> 5< /code>) 并接受另一个参数 (
y
)。当您将 6 传递给
add5ToNumber
时,它会将保存的x
(5) 和给定的y
(6) 传递给addTwoNumbers,结果为 11
addTwoNumbers
accepts 2 arguments (x
andy
).add5ToNumber
is assigned to the output of callingaddTwoNumbers
with only 1 argument, which results in another function that "saves" the first argument (x -> 5
) and accepts one other argument (y
).When you pass 6 into
add5ToNumber
, its passing the savedx
(5) and the giveny
(6) intoaddTwoNumbers
, resulting in 11