在深刻到函数式编程思想以前,了解函数式独有的类型是很是有必要的。函数式类型跟OO语言中的数据结构大相径庭,这也致使使用函数式编程语言来解决问题的思路跟OO的思路有明显的区别。编程
什么是类型?类型在编程语言中有什么做用呢?通常来讲,类型有两个做用:数据结构
元组是函数式编程语言中的经常使用类型,同时在.NET 4.0中被引入到了C#中。可是在C#中几乎不太会用到这种类型,可是在函数式编程语言中却随处可见。
例如在C#中这样使用元组:编程语言
var s = new Tuple<int, int>(1, 2); var fist = s.Item1;
在F#中函数式编程
let t = 1,2 let first = fst t //提取第一个元素 let second =snd t //提取第二个元素 let f s = t //经过解构提取元素
Record type是F#中最经常使用的类型。常常被用来对领域建模(Domain modeling)。例如定义一个矩形数据结构:函数
type Rect = { Left: float32 Top: float32 Width: float32 Height: float32 }
这看起来跟OO语言中对class的定义是很类似的,比如在某个class中声明了一组属性。使用起来也简单:单元测试
let rc = { Left = 10.0f; Top = 10.0f; Width = 200.0f; Height = 200.0f }
你能够把它当作一个简单的class,可是从定义和使用都能看出来Record type更加简单和直接一些。而且咱们并无在Record type里设计一些方法,这跟class有本质的区别。
Record type还支持“复制一个现有记录并进行一些修改”:测试
let rc2 ={ rc with Left = rc.Left + 100.0f }
C#中的class是没有这种能力的,你不得不显示复制全部属性。
另外Record type自动实现了equal操做符:翻译
type Name = { First:string ; Last:string} let jim = { First ="Jim"; Last = "Dan"} let jim2 = {First = "Jim"; Last = "Dan"} let isSame = jim = jim2 //true
考虑下面的Contact领域模型:设计
type Contact = { FirstName: string; MiddleName: string; LastName: string; EmailAddress: string; Address1: string; Address2: string; City: string; State: string; Zip: string; }
若是你把它当作一个class也是可行的,实际上在OO语言里咱们也常常设计这样的class。这样的模型定义犯了三个错误:code
组合
,组合不但体如今函数之间的组合,类型也是可组合的:type PersonalName = { FirstName: string; MiddleName: string option; LastName: string; } type EmailContactInfo = { EmailAddress: string; IsEmailVerified: bool; } type PostalAddress = { Address1: string; Address2: string; City: string; State: string; Zip: string; } type PostalContactInfo = { Address: PostalAddress; IsAddressValid: bool; } type Contact = { Name: PersonalName; EmailContactInfo: EmailContactInfo; PostalContactInfo: PostalContactInfo; }
中文翻译过来叫作可区分联合
,这种类型试图为不一样的选项进行建模,因此你能够把他理解为选项类型
。
举个例子:“如今温度是多少?“
如何对如今的温度建模?你问的是摄氏度呢仍是华氏度呢?若是是摄氏度即38°,若是单位是华氏度,则为100.4°。
type Temperature = | F of float | C of int let tempNow = C(30) let tempNow2 = F(100.4)
只有一个选项的类型:
type EmailAddress = EmailAddress of string let email = "a" |> EmailAddress let emails = ["a"; "b"; "c"] |> List.map EmailAddress
选项类型
在F#是很是经常使用的领域模型建模类型,好比设计一个关于支付的模型,在OO语言中,你可能会这样作:
interface IPaymentMethod { } class Cash : IPaymentMethod { } class Cheque: IPaymentMethod { } class Card : IPaymentMethod { } ...
在函数式语言中利用选项类型
能够轻松搞定:
type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber
OO思想中经过抽象接口和定义派生类来实现这个模型。函数式语言则利用选项类型
把模型核心内容经过尽量少的代码展示出来。
此时你也许会有所疑虑,在OO的设计中,每种支付方式都是一个独立的实现,因此每种支付方式的具体行为就能够设计在具体的实现中,例如Payment的过程。不一样的支付方式显然须要不一样的支付过程,这种设计在OO中的好处是显而易见的。
在选项类型
中,彷佛把三种不一样的支付方式揉在了一块,那么每种支付方式的支付过程这种行为怎么实现呢?答案是模式匹配
,咱们将在下节介绍。