假设有一个体育场,行号是A1-10,然后是B1-10,依此类推,直到ZZ
如何创建自定义数据类型并使用它来表示Haskell中的席位?
答案 0 :(得分:3)
您可以将您的枚举视为由三部分组成
第一部分和第二部分都依赖于"字母"的概念,所以让我们来定义
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}}和'-'
。由于我按字母顺序枚举了元素,因此'^'
等自动获取的实例表现正常。
我们可能确实希望利用Ord
是Letter
的子集这一事实,所以我们也要写出预测。
- 因为每个字母都是一个字符,所以总是有效。
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)取其Digit
和div
对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
类型分别注入其超集类型Digit
和Char
的能力几乎肯定会派上用场。