Haskell自定义数据类型和表示

时间:2015-03-05 09:56:37

标签: haskell

假设有一个体育场,行号是A1-10,然后是B1-10,依此类推,直到ZZ

如何创建自定义数据类型并使用它来表示Haskell中的席位?

1 个答案:

答案 0 :(得分:3)

您可以将您的枚举视为由三部分组成

  • 第一个字母,
  • (可选)第二个字母,
  • 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包含额外内容的问题,例如{ {1}}和'-'。由于我按字母顺序枚举了元素,因此'^'等自动获取的实例表现正常。

我们可能确实希望利用OrdLetter的子集这一事实,所以我们也要写出预测。

- 因为每个字母都是一个字符,所以总是有效。

Char

现在我们使用"数字从1到10"

播放相同的游戏
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

我们甚至可以编写其他方式将data Digit = D1 | D2 | D3 | D4 | ... deriving ( Eq, Ord, Show ) digitToInt :: Digit -> Int digitToInt = ... intToDigit :: Int -> Maybe Digit intToDigit = ... 撤回到Int。例如,我们可以(1)取整数的绝对值,然后(2)取其Digitdiv对10个席位。这将导致mod分配和行号。

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 Nothing小于Show x且记录排序为词典。我们还可以编写一个非常简单的展示实例

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 Letter类型分别注入其超集类型DigitChar的能力几乎肯定会派上用场。