Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 我应该在什么时候以咖喱形式编写函数?_F#_Functional Programming - Fatal编程技术网

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

我最近开始学习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 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
表示最大公分母,然后是文本中所称的高阶函数,其中