アルファベットの繰り上がり #2

Enum クラスのデータを定義するというネタで。これで任意区間を簡単に取得できる。

import Char

alpha_succ :: String -> String
alpha_succ [] = "A"
alpha_succ ('Z':cs) = 'A' : alpha_succ cs
alpha_succ (c:cs) = succ c : cs

num2alpha :: Int -> String
num2alpha = reverse . num2alpha'
  where
    num2alpha' n
      | n < 26    = [chr (ord 'A' + n `mod` 26)]
      | otherwise = let m = (n - 26) `div` 26
                    in chr (ord 'A' + n `mod` 26) : num2alpha' m

alpha2num :: String -> Int
alpha2num s = foldl1 (\x y -> x * 26 + 26 + y) $ map c2n s
  where
    c2n c = ord c - ord 'A'

data AlphabetNumber = AlphabetNumber String
instance Show (AlphabetNumber) where
  show (AlphabetNumber s) = s

instance Enum (AlphabetNumber) where
  toEnum n = AlphabetNumber (num2alpha n)
  fromEnum (AlphabetNumber s) = alpha2num s
  succ (AlphabetNumber s) = AlphabetNumber ((reverse . alpha_succ . reverse) s)

an :: String -> AlphabetNumber
an s = AlphabetNumber s

main = print . (take 100) $ [an "A" .. ]