如果你也会C#,那不妨了解下F#(2):数值运算和流程控制语法
本文链接:http://www.cnblogs.com/hjklin/p/fs-for-cs-dev-2.html
一些废话
一门语言火不火,与语言本身并没太大关系,主要看语言的推广。
推广得好,用的人多,问题也能及时得到解决,用的人就越多,这是一个良性循环,即使语言本身有很多不足也很快能得到解决。
但有的语言本身很好,使用者却不多,缺少交流和推广,致使进入恶性循环。
《黑客与画家》作者把Lisp吹上天,但却没见他继续推广,至今在使用的团队和行业还是很有限。
而说到F#,国内也出过F#的高校教材,不知道是否有高校开课,在企业上更是很少使用。
“赵姐夫”(博客)在10年说过要做F#在国内的推广者,几年过去了,也是无声无息。
那为什么在2016年的现在,那么多新的语言和技术,我们还要来了解F#呢?
- F#和C#一样,也是基于.Net平台的语言,了解了语法后,就能快速地使用.Net框架甚至C#编写的框架,
而且在学习过程中.Net框架中很多以前不理解的东西,通过F#就变得很容易理解了。作为.Net程序员,还是值得了解的。 - 函数式语言的“天然支持异步和并行”的能力,也使得多线程开发变得简单。
C#在最近的版本中经常得益于F#对.Net框架的推进,如加入了async
关键字,有Tuple
了(虽然在语法层面不支持)等等。 - 在最近发布的.Net Core中,也可以通过
dotnet new -l f#
来创建F#项目。.Net Core里F#的坑,这里就不细说了。 😅 通过.Net博客,也可以发现越来越多人在使用F#。
F#并无法替代C#,但两者却能起到互补的作用。
记得《七周七语言》里说过:
每学一门新的语言,思维方式都会发生改变。编程语言亦是如此。
作者在书中说,每学习一门语言都会去找互动教程,但大多数情况下并找不到称心如意的。
若想领会一门语言的精髓,它(指互动教程)可就无能为力了。我想要的是那种痛快淋漓、深入探索语言本质的感觉。
我是没有作者的这种能通过探索语言本质的能力来介绍F#,但希望也能让大家发现F#语言的动人心弦之处。
废话说得有点多了,下面继续介绍F#吧。
数值运算
我们再翻出上一篇的小例子:
let mutable sum = 0
for i = 0 to 100 do
if i%2 <> 0 then sum <- sum + i
printfn "0到100中的奇数的和为%A" sum ;;
四则运算和模运算(取余)不必多说,但对于浮点数(float
和float32
)类型,还支持**
(幂)语法。
2. ** 3.;; // val it : float = 8.0
像abs
、sin
等这些基本数学函数在F#里也包含在操作符(Operators)的模块里,所有操作符可在MSDN文章(Core.Operators Module(F#))查看。
大整数(BigInteger)
在上一篇的数值类型对比中,我们可以看出,F#在语法层面上支持大整数。
大整数于.Net 4.0添加到框架中,在System.Numerics
模块里。F#创建项目时默认引用了此dll。(大整数也支持**
运算符,但指数必须为int
,其实就是Pow
方法。)
let bigInt = 4325I;; //相当于C#的 var bigInt = new BigInteger(4325);
3I ** 8;; // val it : System.Numerics.BigInteger = 6561 ...
在内存足够的情况下,BigInteger
支持任意大的整数。 通过大整数,我们也可以自己实现大实数,或直接使用第三方类库。
数值类型转换
在F#中,没有隐式类型转换,就连int
到long
或float
也没有。所以,数值类型转换使用返回对应类型的转换函数:
int 2.5;; // 2
float "3.1415" // 3.1415
(float 2)**(float 3);; //8.0
当然也可以使用.Net框架的System.Convert
静态类。上述方法在转换字符串时也是调用的此方法。
位运算符
F#中的位运算符均使用三重符号:
运算符 | 名称 | 示例 | 结果 |
---|---|---|---|
&&& | 与 | 0b1111 &&& 0b0011 | 3 |
||| | 或 | 0xFF00 ||| 0x00FF | 65535 |
~~~ | 取反 | ~~~0b0011 | -4 |
^^^ | 异或 | 0b0011 ^^^ 0b0101 | 6 |
<<< | 左移 | 0b0001 <<< 3 | 8 |
>>> | 右移 | 0b1000 >>> 3 | 1 |
注:“或”使用|||
,博客园的Markdown渲染时,竟然不支持表格里的|
转义。😅
比较
因为函数式语言中,数值不可变,所以=
在F#中并不是赋值符号。
=
在F#执行相等比较操作,而不等则为<>
,这两个符号与C#有异:
5=8 ;; //false
"ax"<>"ay" ;; //true
那就会有人说,F#也有可变的值啊,怎么赋值呢!没错,在上面的示例代码中sum
为可变值,每次循环通过<-
符号改变其值。好诡异但又好有道理的符号啊! 😲
所以需要注意,C#中的 int i = 1;
其实是相当于F#中的 let mutable i = 1
。因为C#默认创建的是可变类型。 请查看后面的while循环介绍。
此外,F#中还有一个compare
函数用来比较两个值:
compare 31 31;; // 0
compare 5 4;; // 1
(*
compare x y
若x > y则返回1;若x < y则返回-1;若x = y则返回0
*)
这个比较在C#中有实现过IComparable
接口的应该了解,其实compare
函数的参数就是需要实现了IComparable
接口的类型。
在.Net中,比较是一个复杂的话题,在此就不展开了,可参考MSDN文章(Object.Equals方法和IComparable 接口)。
流程控制语法
for循环语句
下面是0到100的循环,从0打印到100:
- C# 代码:
for (int i=0; i<=100; i++) { System.Console.WriteLine(i); }
- F# 代码:
for i=0 to 100 do printfn "%i" i
for i in [0..100] do printfn "%i" i
for i=100 downto 0 do printfn "%i" i //逆向循环,从100到0
F#版本中的[0..100]
是创建一个从0到100的列表(list
),在之后列表模块会进行介绍。
遗憾的是for ... to
和for ... downto
语句无法创建如for (int i=0; i<=100; i+=2)
这种间隔不为1的循环,只能使用for ... in
再加上一个列表。
while循环语句
用while
循环实现的从0打印到100:
- C# 代码:
int i = 0;
while (i <= 100)
{
System.Console.WriteLine(i);
i++;
}
- F# 代码:
let mutable i = 0
while i <= 100 do
printfn "%i"
i <- i + 1
需要注意的是,F#中并没有do...while
的循环,在for
循环和while
循环中,也都没有break
和continue
关键字。
刚开始接触F#或习惯了C#的循环语句可能会不习惯,但当你熟悉了函数式编程的思想后,会发现这些在F#中都是不重要的,甚至循环语句都是不必要的。
同时,也尽量不要使用可变类型。因为值的不可变性,使多线程编程变得简单;而在C#中,因为值默认为可变的,使程序在多线程运行中增加了很多不确定因素。
条件语句之if
在上面的示例代码中已经使用过if
语句。
在F#中,if
语句的完整结构是这样的:
if x>y then "x大于y"
elif x<y then "x小于y"
else "x等于y"
if x>y then printfn "x大于y" //if分支无返回值
在F#的if语句中,每个分支必须返回相同类型的值,但不需要return
关键字(在介绍函数时会涉及)。
如果if分支没有返回值(即返回unit
),则else为可选的;否则,必须有else分支。(类似于C#的?:
操作符,但F#中没有这个操作符。)
C#中的else if
在F#中为elif
。
条件语句之switch(match)
在C#中,还有一种分支结构的语句是使用switch...case
。在F#中类似的语法是match...with
。
- C# 代码:
int i = 1;
switch (i)
{
case 1:
Console.WriteLine("this is one");
break;
case 2:
Console.WriteLine("this is two");
break;
case 3:
Console.WriteLine("this is three");
break;
default:
Console.WriteLine("this is something else");
break;
}
- F# 代码:
let i = 1
match i with
| 1 -> printfn "this is one"
| 2 -> printfn "this is two"
| 3 -> printfn "this is three"
| _ -> printfn "this is anything else"
其中_
为通配符,与C#switch
中的default
类似。
但F#中的match
语句功能非常强大,可查看MSDN文章Match表达式(Match Expressions)和
模式匹配(Pattern Matching)。
模式匹配在函数式编程中有着作用,在之后的函数式编程中也会进行介绍。
在下一篇中,我们来了解数组和列表,以及一些F#特有的类型。
- 若您觉得本文对您有帮助,请点一下“推荐”按钮。你的支持我写作最大的动力。
- 才疏学浅,文章中难免会有不足和错误之处。希望大家能不吝作出批评指正。
- 欢迎转载,但未经本人同意,必须在文章页面明显位置给出作者和原文连接。谢谢配合!