假设有一个体育场,排号是A1-10,然后是B1-10,等等,直到ZZ。
如何创建自定义数据类型并使用它来表示Haskell中的座位?
发布于 2015-03-05 12:38:22
您可以认为枚举是由三个部分组成的。
第一部分和第二部分都依赖于“字母”的概念,所以让我们来定义一下
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这样的自派生实例运行正常。
我们可能确实想利用Letter是Char的一个子集这一事实,所以我们也要编写预测。
-这个总是有效的,因为每个字母都是一个字符.
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)取其div和mod对10个座位。这将导致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很可能,将Letter和Digit类型分别注入其超集类型Char和Int的能力在以后编写代码时几乎肯定会派上用场。
https://stackoverflow.com/questions/28874880
复制相似问题