2015-03-05 2 views
2

Say есть стадион и номер строки является чем-то вроде А1-10, затем B1-10 и так далее до ZZHaskell типа пользовательских данных и reprsentation

Как не мне сделать пользовательский тип данных и использовать его для представляют место в Haskell?

+0

Используйте тип данных записи для хранения первой и второй частей отдельно. – Sibi

+0

«До ZZ» означает, что после 'Z' вы попадаете в' AA', затем 'AB'? –

+0

@BartekBanachewicz yes thats right – xcoder

ответ

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, содержащих дополнительные вещи, такие как '-' и '^'. Поскольку я перечислял элементы в алфавитном порядке, автоподавленные экземпляры вроде 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 снова полностью автоматически, как правильно 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 и Int соответственно почти наверняка пригодятся при написании кода позже ,

+1

Я бы вывел 'letterToChar' и' charToLetter' из 'fromEnum' и' toEnum', плюс некоторые проверки границ. (Конечно, после 'получения (..., Enum)'). – chi

+0

Я, вероятно, слишком серьезно рискнул бы опечатать ошибки. По какой-то причине я чувствовал, что его полное описание было бы иллюстративным. –

Смежные вопросы