什么时候应该以咖喱形式写我的功能?

Too*_*one 25 f# functional-programming

我最近开始学习F#并遇到curried函数,用于简单示例,如下所示:

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

let sales (p,n) = p * (float n);;
Run Code Online (Sandbox Code Playgroud)

该函数的类型为

val sales : p:float * n:int -> float
Run Code Online (Sandbox Code Playgroud)

即采取对floatint并返回float.

我们可以把它写成一个curried函数

let salesHi p n = p * (float n);;
Run Code Online (Sandbox Code Playgroud)

该函数的类型为

val salesHi : p:float -> n:int -> float
Run Code Online (Sandbox Code Playgroud)

即需要一个float和返回功能intfloat.

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

sales (0.99, 100);;
salesHi 0.99 100;;
Run Code Online (Sandbox Code Playgroud)

两者都给

val it : float = 99.0
Run Code Online (Sandbox Code Playgroud)

然而,通过咖喱功能,我可以为特定项目提供价格以获得新功能.例如

let salesBeer =  salesHi 5.99;;
let salesWine =  salesHi 14.99;;
Run Code Online (Sandbox Code Playgroud)

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

另外,我注意到内置的运算符如+定义为函数,所以我可以编写,例如:

let plus2 = (+) 2;
List.map plus2 [1;3;-1];;
Run Code Online (Sandbox Code Playgroud)

得到

val it : int list = [3; 5; 1]
Run Code Online (Sandbox Code Playgroud)

这似乎是一件好事.因此,当我想在一个可以使用n > 1参数的命令式语言中实现一个函数时,我是否应该总是在F#中使用一个curried函数(只要参数是独立的)?或者我应该采取简单的路线,n并在必要时使用常规功能与-tuple和咖喱?或者是其他东西?

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

Tom*_*cek 31

当你在curried和tupled形式之间进行选择时,要考虑的主要问题是你作为参数的元组是否意味着什么.

Tupled形式.例如,float * float可能代表一个范围,然后使用tupled形式是个好主意.

let normalizeRange (lo, hi) = if hi < lo then (hi, lo) else (lo, hi)
let expandRange by (lo, hi) = (lo - by, hi + by)
Run Code Online (Sandbox Code Playgroud)

关于这一点的好处是你可以编写适用于范围的函数.你可以写例如:

randomRange() |> normalizeRange |> expandRange 10
Run Code Online (Sandbox Code Playgroud)

咖喱形式.另一方面,如果所有参数的元组不是具有某些有用含义的独立值,则curried形式是更好的选择.例如,幂函数pown 2.0 10- 两个参数是幂和指数,但你不可能(2.0, 10)在你的程序中的其他地方使用元组.

当你有一个"更重要"的参数时,curried表格也很有用,因为那时你可以使用流水线.例如,List.map必须通过咖喱来允许:

[1 .. 10] |> List.map (fun n -> n + 1)
Run Code Online (Sandbox Code Playgroud)