函数式编程之-初窥F#
大量讲解函数式编程语言的书籍最终都会用Fuctor,Monad,Monoids,范畴论等各种词汇吓退命令式语言玩家,所以我试图避开这些问题,揭开这些复杂词汇带来的具有实战意义的成果。另外我会尽量使用C#语言来描述函数式编程思想,因为C#某些语法和特性来自于函数式语言的启发,但C#终究并不是正统的函数式语言,随着对话题的深入,我们不可避免要使用F#来描述某些特性。所以本文会对F#的基础语法做一些简单了解,本文并不是一个纯粹的F#教程,只会提及必要的F#语法,最终循序渐进穿插在整个文章中。
函数是一等公民
在函数式语言里,函数被设计为一等公民,也就是说函数跟int, bool等类型并没有什么区别,例如在命令式语言的函数定义中,参数可以是int值,那么在函数式语言里,参数也可以是一个函数。这种特性在C#其实也是工作的:
public void Convert(Func<int,bool> selector){ }
这种设计在函数式语言里会有更进一步的体现:
在F#中声明一个简单类型用let
:
let x = 6
声明一个函数:
let f x = x + 1
或者:
let f = fun x -> x + 1
无论是申明类型还是函数,都用let
,这并不是一个巧合,因为在语言设计者眼里,函数和其他类型都是一样的。
另外需要注意,不要看到上面的代码认为F#是一门动态语言,F#毫无疑问是一门静态语言,通过type inference来工作。它要比C#中的var
强大的多,只有在少数情况下需要加类型声明,考虑下面的例子:
let stringLength x = x.Length
上面的代码并不能正常工作,仅仅通过x.Length无法推断出x的类型,此时需要显示标注类型:
let stringLength (x:string) = x.Length
当然你还可以向其它语言那样,标注函数的返回值类型,虽然此时此刻这一步并不是必须的:
let stringLength (x:string) :int = x.Length
理解unit类型
我们在上一篇对数学中的函数
做了描述,其中提到对于任意的输入总会有唯一的输出值与之对应,考虑下面的代码:
let printNumber x = printf "%i" x
这段代码不论你输入什么样的x,它只是打印了一个数字(副作用),他的返回值是什么?不像C#中的void
,F#会返回一个真实的类型unit
,注意unit
并不是null
或者void
,他是一个类型,如int
一样。
理解tuple类型
F#里有一些常用的数据结构,例如tuple
,Record types
,Discriminated Union
,Option
,List
,不要担心,目前你只需要知道tuple
就可以了。
除了诸如int
, string
等类型,如何快速的组合几个类型在一起呢?声明一个类?答案是:No
, 比如("hello", 1)就是有一个string
和int
组合在一起的tuple类型,他的类型为string * int
。例如下面的函数:
let sum (x, y) = x + y
它的方法签名是:sum : x:int * y:int -> int
即函数名为sum
,接受int * int
类型的一个tuple
,返回int
类型。
如果要接受两个int
类型的参数应该这样定义的:
let sum x y = x + y
好了,F#的基本介绍已经完毕,下一篇将介绍Currying
,他是函数式编程语言中常用的模式之一,想要继续了解的朋友继续关注下一篇。