F# 我应该在什么时候以咖喱形式编写函数?
我最近开始学习F#,遇到了一些简单的函数示例,例如: 考虑一个函数,该函数通过将价格F# 我应该在什么时候以咖喱形式编写函数?,f#,functional-programming,F#,Functional Programming,我最近开始学习F#,遇到了一些简单的函数示例,例如: 考虑一个函数,该函数通过将价格p乘以售出的单位数量n来计算销售额 let sales (p,n) = p * (float n);; 此函数的类型如下所示 val sales : p:float * n:int -> float val salesHi : p:float -> n:int -> float i、 e.获取一对float和int并返回一个float 我们可以把它写成一个curried函数 let sal
p
乘以售出的单位数量n
来计算销售额
let sales (p,n) = p * (float n);;
此函数的类型如下所示
val sales : p:float * n:int -> float
val salesHi : p:float -> n:int -> float
i、 e.获取一对float
和int
并返回一个float
我们可以把它写成一个curried函数
let salesHi p n = p * (float n);;
此函数的类型如下所示
val sales : p:float * n:int -> float
val salesHi : p:float -> n:int -> float
i、 e.接受一个float
并将int
函数返回到float
在简单的情况下,这似乎没有什么区别
sales (0.99, 100);;
salesHi 0.99 100;;
两者都给予
val it : float = 99.0
然而,使用curried函数,我可以输入特定项目的价格,以获得新函数。例如
let salesBeer = salesHi 5.99;;
let salesWine = salesHi 14.99;;
然后salesBeer 2
给出11.98
和salesweer 2
给出29.98
另外,我注意到内置操作符,如+
被定义为函数,因此我可以编写,例如:
let plus2 = (+) 2;
List.map plus2 [1;3;-1];;
得到
val it : int list = [3; 5; 1]
这似乎是件好事。因此,当我想用命令式语言实现一个函数时,如果该函数采用了n>1
参数,那么我是否应该在F#中始终使用curried函数(只要参数是独立的)?或者我应该采取简单的方法,在必要时使用带有n
-元组和curry的常规函数吗?还是别的什么
F#程序员如何决定何时以咖喱形式生成函数,还是使用带有元组的正则函数
或者我应该采取简单的方法,并在必要时使用带有n元组的正则函数和curry
你觉得做更多工作更简单的是什么?让东西x y z=。。。不仅仅是打字比let stuff(x,y,z)少,实际上语言所做的工作更少。第二个版本必须分配一个元组,然后将元组分解为参数,而第一个版本只使用参数
咖喱格式是用F#编写函数的惯用方式。除非数据已经被存储为元组,否则我真的无法想出一个很好的理由来使用元组。 < P>当你在Currube和tuple形式之间选择时,要考虑的主要问题是,作为参数的元组是否意味着什么。 元组表单。例如,
float*float
可能表示一个范围,因此最好使用元组表单
let normalizeRange (lo, hi) = if hi < lo then (hi, lo) else (lo, hi)
let expandRange by (lo, hi) = (lo - by, hi + by)
咖喱格式。另一方面,如果所有参数的元组不是具有某些有用意义的独立值,则咖喱格式是更好的选择。例如,幂函数pown 2.0 10
——这两个参数是幂的数字和指数,但您不太可能在程序中的其他地方使用元组(2.0,10)
当您有一个“更重要”的参数时,咖喱格式也很有用,因为这样您就可以使用管道。例如,必须使用List.map
来允许:
[1 .. 10] |> List.map (fun n -> n + 1)
元组形式实际上有点危险。它可能看起来类似于ALGOL风格的语言(占流行语言的90%),但工作原理不同 考虑这一点:
foo bar(x,y)
在所有允许这种语法的ALGOL风格语言中,这意味着“使用x
和y
作为参数调用bar
,并将结果传递给foo
”——当foo
不一定是一个方法时(它可以是语法,就像2.*Python中的print
)
然而,在Lambda风格的语言(如ML、Haskell和F#)中,这意味着“使用bar
作为参数调用foo
,然后使用tuple(x,y)
作为参数调用结果(这是一个函数)
如果您不熟悉Lambda风格的语言,这可能会让人感到非常困惑。现在,如果您使用的是咖喱形式,则等效形式为:
foo bar x y
这和foo-bar(x,y)一样错误-但也没有那么令人困惑!即使是不熟悉Lambda风格语言的程序员也很容易发现
bar
不是foo-bar x y
中调用的第一个函数。错误马上就清楚了。另一个考虑因素-如果您计划与C或VB.NET进行互操作,请不要另一方面,从C#/VB.NET的角度来看,元组形式是一组普通的参数,使用起来非常自然。术语高阶函数通常指接受/返回函数的函数,而您的问题似乎是元组“vs”多个参数“。你可能想改写一下。也就是说,我更喜欢多参数函数,这是为了讨价还价。@MarcinŁoś感谢我添加了一些关于sales
和salesHi
类型的内容,以使其更清晰。也有可能我在我的问题中没有使用标准术语。你所谓的“高阶”函数实际上是一个函数,而不是元组形式的函数。在使用函数语言时,函数通常采用咖喱形式,因为这允许部分应用。@Lee感谢您的澄清和编辑。在我正在阅读的文本中,像(+)
和sales
这样的函数被称为高阶函数,而currying甚至不在索引中(不过它出现在练习中)。我之所以这样说,是因为我似乎使用了不恰当的术语,但考虑到这本书所说的以及这里经验丰富的F#ers所说的,我不确定什么是正确的。也许“simpler”这个词用错了。也许我应该说得更熟悉一些,就像我一直在使用的命令式语言一样。在我正在阅读的教科书中,首先介绍了采用元组的函数,例如,gcd:int*int->int
表示最大公分母,然后是文本中所称的高阶函数,其中