在深刻到函數式編程思想以前,瞭解函數式獨有的類型是很是有必要的。函數式類型跟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中的好處是顯而易見的。
在選項類型
中,彷佛把三種不一樣的支付方式揉在了一塊,那麼每種支付方式的支付過程這種行爲怎麼實現呢?答案是模式匹配
,咱們將在下節介紹。