第二章:data和模式匹配

夢飛發表於2017-02-23

資料和資料型別是程式設計過程中最核心的部分。本章內容如下:資料型別的data語法結構;建構函式;模式匹配;data的記錄語法,資料項的提取更新。

1.資料宣告data:data是Haeklell中最重要的關鍵字之一 enter image description here

  • data Position 定義了一個新的資料型別Position
  • MakePosition Double Double 指定了如何建立一個Position資料型別的資料
  • MakePosition 被稱為型別Position 的建構函式
  • Haskell中,除建構函式外,其他函式都應以小寫字母開頭
  • 中綴建構函式

2.模式匹配(pattern match):簡單來講就是將資料和“變數”對應起來。例如Position型別的點pointA(x1,y1),用PointA = MakePosition 3 4 去匹配 MakePosition x y,將得到x=3, y=4。我們可以定義函式distance來計算點PointA 和PointB之間的距離

distance :: Position -> Position ->Double
distance p1 p2 =
     case p1 of
            MakePosition x1 y1 ->
               case p2 of 
                     MakePosition x2 y2 -> sqrt ((x1-x2)^2 + (y1-y2)^2)
  • 用模式匹配來繫結值

    enter image description here

  • @pattern

    someFunction p1@(MakePosition x1 y1) p2@(MakePosition x1 y1)
    

3.各式各樣的資料型別

  • 多建構函式

    data Position = Cartesian Double Double | Polar  Double Double 
    Cartesian 1.5 2 :: Position
    Polar 0.2 1 :: Position
    -- | 表示選擇,它連線了所有可能的建構函式
    
    
    --則此時上述的distance 函式需重新定義來適應不同的情形
    distance :: Position -> Position ->Double
    distance (Cartesian x1 x2) (Cartesian x1 x2) = ...
    distance (Cartesian x1 x2) (Polar x1 x2) = ...
    distance (Polar x1 x2) (Cartesian x1 x2) = ...
    distance (Polar x1 x2) (Polar x1 x2) = ...
    

如上面的distance有四種匹配模式,如果模式重複或少寫自己又沒有發現時,GHC的完備性檢查(exhaustiveness checking)可以幫助你。GHCi中通過 :set -Wall 開啟

  • 無引數建構函式:不僅data宣告的型別不一定只有一種建構函式,建構函式也不一定要接收引數

     data Bool = True | False
     --這個型別只可能有兩個值
    
  • data與型別變數:為了提高程式碼的適用性

    enter image description here

那麼加法的適用範圍不僅僅是Double型別的,可以是Num類中的任何一種

注:data宣告中,=右側出現的型別變數,都必須出現在=左側,反過來沒這個規定。在某些情形下,有實際應用,例如 data Maybe a = Just a | Nothing用來處理失敗的問題

  • 記錄語法(record syntax):只匹配需要的部分

    getX :: Position -> Double
    getX p = let MakePosition x _ = p in x          -- _表示佔位符
    
    
    getY :: Position -> Double
    getY p = let MakePosition _ y = p in y
    
    
    --和如下定義等價
    data Position = MakePosition { getX :: Double, getY :: Double}  
    

    enter image description here

  • 建構函式後面的{label1 :: Type1, label2 :: Type2 ...} 定義了一個記錄,實際上相當於額外定義了提取函式label1, label2

  • 用下面語法建立資料與更新資料

    data Position = MakePosition { getX :: Double, getY :: Double}  
    pointFoo = MakePosition {getY = 4, getX = 3}
    -- 相當於 pointFoo = MakePosition 3 4
    
    
    PointBar = pointFoo{getY = 5}
    -- 相當於 pointBar = MakePosition 3 5
    

    4.三種程式碼(layout)排版規則

    case x of 
        patternA -> ...
        patternB -> ...
    
    
    case x of patternA -> ...
              patternB -> ...
    
    
    case x of {patternA -> ...; patternB -> ...}
    

    出於簡潔考慮,長的情況用第一種,短的用第二種,除非特殊需求,一般不用第三種排版。

相關文章