我什么时候应该以柯里化形式编写我的函数? [英] When should I write my functions in curried form?

查看:18
本文介绍了我什么时候应该以柯里化形式编写我的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近开始学习 F# 并遇到了一些简单示例的柯里化函数,例如:

I've recently started learning F# and come across curried functions for simple examples such as the following:

考虑一个函数,它通过将价格 p 乘以销售单位数 n 来计算销售额.

Consider a function that calculates sales by multiplying price p by number of units sold n.

let sales (p,n) = p * (float n);;

该函数的类型为

val sales : p:float * n:int -> float

即取一对 floatint 并返回一个 float.

i.e. take a pair of float and int and returns a float.

我们可以把它写成一个柯里化函数

We can instead write this as a curried function

let salesHi p n = p * (float n);;

该函数的类型为

val salesHi : p:float -> n:int -> float

即接受一个 float 并将 intfunction 返回给 float.

i.e. takes a float and returns a function of int to float.

在简单的情况下,这似乎没有区别

In simple cases this seems to make no difference

sales (0.99, 100);;
salesHi 0.99 100;;

都给

val it : float = 99.0

但是,使用咖喱函数,我可以输入特定商品的价格以获得新功能.例如

However with the curried function I can feed in the price for particular items to get new functions. E.g.

let salesBeer =  salesHi 5.99;;
let salesWine =  salesHi 14.99;;

然后 salesBeer 2 给出 11.98salesWine 2 给出 29.98.

Then salesBeer 2 gives 11.98 and salesWine 2 gives 29.98.

另外,我注意到像+这样的内置操作符被定义为函数,所以我可以写,例如:

Also, I've noticed that built-in operators such as + are defined as functions, so I can write, for example:

let plus2 = (+) 2;
List.map plus2 [1;3;-1];;

并得到

val it : int list = [3; 5; 1]

这看起来是一件好事.所以当我想用命令式语言实现一个函数时,它会采用 n >1 参数,例如,我是否应该始终在 F# 中使用柯里化函数(只要参数是独立的)?或者我应该走简单的路线并使用带有 n-tuple 的常规函数​​,并在必要时稍后使用?或者别的什么?

This seems like a good thing. So when I want to implement a function in an imperative language that would have taken n > 1 arguments, should I for example always use a curried function in F# (so long as the arguments are independent)? Or should I take the simple route and use regular function with an n-tuple and curry later on if necessary? Or something else?

F# 程序员如何决定何时以柯里化形式创建函数或使用带有元组的常规函数​​?

How do F# programmers decide when to make a function in curried form or use a regular function with a tuple?

推荐答案

当您在柯里化和元组形式之间进行选择时,要考虑的主要问题是您将作为参数的元组意味着 任何东西.

When you're choosing between curried and tupled form, the main thing to consider is whether the tuple that you'd take as an argument means anything.

元组形式.例如,float * float 可能代表一个范围,那么最好使用元组形式.

Tupled form. For example, float * float might represent a range and then it is a good idea to use the tupled form.

let normalizeRange (lo, hi) = if hi < lo then (hi, lo) else (lo, hi)
let expandRange by (lo, hi) = (lo - by, hi + by)

这样做的好处是您可以组合在范围内工作的函数.例如,您可以编写如下内容:

The good thing about this is that you can then compose functions that work on ranges. You can for example write something like:

randomRange() |> normalizeRange |> expandRange 10

柯里化形式. 另一方面,如果所有参数的元组不是具有某些有用意义的独立值,柯里化形式是更好的选择.例如,幂函数 pown 2.0 10 - 两个参数是幂的数和指数,但您不太可能使用元组 (2.0, 10) 程序中的其他位置.

Curried form. On the other hand, the curried form is a better choice if the tuple of all arguments is not a stand-alone value with some useful meaning. For example, the power function pown 2.0 10 - the two arguments are the number to power and the exponent, but it is unlikely that you'd ever use the tuple (2.0, 10) somewhere else in your program.

柯里化形式在您有一个更重要"的参数时也很有用,因为这样您就可以使用流水线.例如,必须对 List.map 进行柯里化以允许这样做:

The curried form is also useful when you have one "more important" argument, because then you can use pipelining. For example, List.map has to be curried to allow this:

[1 .. 10] |> List.map (fun n -> n + 1)

这篇关于我什么时候应该以柯里化形式编写我的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆