《Haskell趣學指南》筆記之型別(type)

方應杭在飢人谷發表於2019-05-04

系列文章


這本書居然沒有告訴我怎麼加註釋,我自己搜了一下

  • 單行註釋以 -- 開頭
  • 多行註釋用 {- whatever -} 括起來

繼續看書

顯式型別宣告

  • :t <exp> 可以得到對應的型別
  • 型別是大寫字母開頭的
  • 給單引數函式宣告型別,語法是 :: ParamType -> ReturnType
    removeNonUppercase :: [Char] -> [Char] 
    removeNonUppercase st = [ c | c <- st, c ` elem` ['A'..' Z']] 
    複製程式碼
  • 給多引數函式宣告型別,語法是 :: Param1Type -> Param2Type ->ReturnType
    addThree :: Int -> Int -> Int -> Int 
    addThree x y z = x + y + z
    複製程式碼

基本型別

  • Int -- 有界
  • Integer -- 無界,可以存超大整數,效率比 Int 低
  • Float / Double / Bool / Char / String就是[Char]
  • tuple 的型別由其內部的元素型別決定,空 tuple 是一個單獨的型別,只有一個值 ()

型別變數(類似於泛型)

  • head 的型別是 head :: [a] -> a
    • 注意這裡的 a 是小寫,不是大寫,因為 a 是型別變數,不是型別
    • 一般型別變數只使用一個字母,但是用多個字母也不報錯
  • 多型函式:使用了型別變數的函式。

型別類 typeclass

  • 類似於介面,但是它是用來約束型別 type 的。
  • 一個 type 可以是多個 typeclass 的例項,一個 typeclass 可以有多個 type 例項。
  • Eq 是最常見的型別類,Haskell 中標準型別都是 Eq 的例項,Eq 要求它的例項必須實現 ==/= 兩個函式
  • 我們可以看看 == 運算子(也是函式)的型別
    ghci> :t (==) 
    (==) :: (Eq a) => a -> a -> Bool
    複製程式碼
  • 看上面程式碼,型別宣告 a->a->Bool 前面有個 =>,再前面有個 (Eq a)
    • 這個 (Eq a) 叫做型別約束
    • 它約束 a 必須是 Eq 的例項,這樣就保證了 a 必須實現 == 函式,以提供給全域性的 == 函式呼叫
  • Ord 型別類要求例項必須實現 < / <= / > / >= 等比較操作
  • Ord 的有三種值:GT / LT / EQ,可以用 compare 得到
    ghci> compare 1 2
    LT
    複製程式碼
  • Show 型別類要求例項可以表示為字串
  • show 函式可以把任意 Show 例項變為字串
  • Read 型別類跟 Show 相反,它把非字串的東西轉為字串
  • read 函式是 show 的相反操作
    ghci> show True 
    "True"
    ghci> (read "True") || False 
    True 
    複製程式碼
  • 注意直接 read "True" 會報錯,因為 GHCi 需要根據後續的操作來確定你要把字串轉成什麼型別
  • 型別註解:可以使用型別註解來告訴 GHCi 這玩意是什麼型別。read "True" :: Bool 就不會報錯,看起來很像 TypeScript 的 as 關鍵字
  • Enum 型別類要求例項有 successer 後繼和 predecesor 前趨兩個操作。可以使用 succ 函式和 pred 函式得到一個例項的後繼和前驅。
  • Enum 的例子
    • ['a' .. 'e'] -- "abcde"
    • [LT..GT] -- [LT, EQ, GT]
  • Bounded 型別類要求例項有上限和下限
  • 用 maxBound 和 minBound 可以獲取例項的上下限
  • 這兩個函式的型別是 (Bounded a)=> a,這叫多型常量(跟多型函式對應)。
  • maxBound :: (Bool, Int, Char) 會得到每個例項的上限組成的 tuple,即 (True, 2147483647, \1114111)
  • Num 型別類要求例項具有數的特徵。
  • :t 20 的結果是 (Num t)=> t
    • 這很奇怪, 20 的型別居然不是 Int 或者 Integer 或者 Float 之類的,而是這些型別對應的 typeclass 對應的多型常量,有點燒腦。
  • 所有的數都是多型常量,可以具有任何 Num 的例項的特徵,也就是說 20 既可以是 Int / Integer 也可以是 Float / Double 等。
  • Floating 型別要求例項具有浮點數的特徵,如 Float 和 Double 都是 Floating 的例項。
  • sin :: Floating a => a -> a
  • Integeral 型別要求例項具有整數的特徵,如 Int 和 Integer。
  • fromIntegral :: (Num b, Integral a) => a -> b
  • length [1,2,3] + 3.2 會報錯,解決辦法是 fromIntegral (length [12,3]) + 3.2

型別類概覽

  • Haskell 中所有標準 type 都是 Eq 的例項,除了輸入輸出相關型別和函式
  • 目前我們遇到的所有 type 都是 Ord 的例項,除了函式
  • 目前我們遇到的所有 type 都是 Show 的例項,除了函式
  • 目前我們遇到的所有 type 都是 Read 的例項,除了函式
  • Enum 型別類包含的 type 有 () / Bool / Char / Ordering / Int / Integer / Float / Double
  • Bounded 包含的 type 有 Int / Char / Bool 等
  • Num 包含 Int / Integer / Float / Double,只有已經屬於 Show 和 Eq 的型別例項,才能成為 Num 的例項,這是一個先決條件( prerequisite)
  • Floating 包含 Float / Double
  • Integeral 包含 Int / Integer

相關文章