簡體   English   中英

Haskell自定義數據類型和表示

[英]Haskell custom data type and reprsentation

假設有一個體育場,行號是A1-10,然后是B1-10,以此類推,直到ZZ

如何創建自定義數據類型並使用它來表示Haskell的席位?

您可以認為您的枚舉由三部分組成

  • 第一個字母,
  • (可選)第二個字母,以及
  • 1到10之間的數字

第一部分和第二部分都依靠“字母”的概念,因此讓我們定義

data Letter
  = La | Lb
  | Lc | Ld
  | Le | Lf
  | Lg | Lh
  | Li | Lj
  | Lk | Ll
  | Lm | Ln
  | Lo | Lp
  | Lq | Lr
  | Ls | Lt
  | Lu | Lv
  | Lw | Lx
  | Ly | Lz
  deriving ( Eq, Ord, Show )

明確枚舉了這種類型,而不僅僅是使用Char這樣我們就不必擔心大小寫之間的區別,也不必擔心Char包含'-''^' 由於我按字母順序枚舉了元素,因此自動派生的實例(例如Ord行為正常。

我們可能確實想利用LetterChar的子集這一事實,所以讓我們也編寫投影。

-因為每個字母都是一個字符,所以這個總是有效的。

letterToChar :: Letter -> Char
letterToChar l = case l of
  La -> 'a'
  Lb -> 'b'
  Lc -> 'c'
  Ld -> 'd'
  Le -> 'e'
  Lf -> 'f'
  Lg -> 'g'
  Lh -> 'h'
  Li -> 'i'
  Lj -> 'j'
  Lk -> 'k'
  Ll -> 'l'
  Lm -> 'm'
  Ln -> 'n'
  Lo -> 'o'
  Lp -> 'p'
  Lq -> 'q'
  Lr -> 'r'
  Ls -> 's'
  Lt -> 't'
  Lu -> 'u'
  Lv -> 'v'
  Lw -> 'w'
  Lx -> 'x'
  Ly -> 'y'
  Lz -> 'z'


-- This one might fail since some characters aren't letters. We also do
-- automatic case compensation.
charToLetter :: Char -> Maybe Letter
charToLetter c = case Char.toLower of
  'a' -> Just La
  'b' -> Just Lb
  'c' -> Just Lc
  'd' -> Just Ld
  'e' -> Just Le
  'f' -> Just Lf
  'g' -> Just Lg
  'h' -> Just Lh
  'i' -> Just Li
  'j' -> Just Lj
  'k' -> Just Lk
  'l' -> Just Ll
  'm' -> Just Lm
  'n' -> Just Ln
  'o' -> Just Lo
  'p' -> Just Lp
  'q' -> Just Lq
  'r' -> Just Lr
  's' -> Just Ls
  't' -> Just Lt
  'u' -> Just Lu
  'v' -> Just Lv
  'w' -> Just Lw
  'x' -> Just Lx
  'y' -> Just Ly
  'z' -> Just Lz
  _   -> Nothing -- default case, no match

現在我們玩同一游戲,“數字從1到10”

data Digit
  = D1 | D2
  | D3 | D4
  | ...
  deriving ( Eq, Ord, Show )

digitToInt :: Digit -> Int
digitToInt = ...

intToDigit :: Int -> Maybe Digit
intToDigit = ...

我們甚至可以寫出其他將Int縮進Digit 例如,我們可以(1)取整數的絕對值,然后(2)取10個席位的divmod 這將導致Digit分配和行號。

intToDigitWrap :: Int -> (Int, Digit)
intToDigitWrap n = (row, dig) where
  (row, dig0) = n `divMod` 10
  -- we use an incomplete pattern match because we have an invariant
  -- now that (dig0 + 1) is in [1, 10] so intToDigit always succeeds
  Just dig    = intToDigit (dig0 + 1) 

最后的類型很簡單!

data Seat = Seat { letter1 :: Letter
                 , letter2 :: Maybe Letter
                 , digit   :: Digit
                 } deriving ( Eq, Ord, Show )

Ord類型再次完全自動更正,因為任何x Nothing小於Show x ,並且記錄順序是字典式的。 我們還可以編寫一個顯示實例,它非常簡單

prettySeat :: Seat -> String
prettySeat s = 
  let l1 = [Char.toUpper $ letterToChar $ letter1 s]
      l2 = case letter2 s of
             Nothing -> ""
             Just c  -> [Char.toUpper $ letterToChar c]
      dig = show (digitToInt (digit s))
  in l1 ++ l2 ++ "-" ++ dig

在以后編寫代碼時,幾乎肯定可以將LetterDigit類型分別注入其超集類型CharInt會派上用場。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM