「第24回オフラインリアルタイムどう書く」を Haskell で。

「第24回オフラインリアルタイムどう書く」の問題を Haskell で解いてみました。

「平方数」と[立法数」は Haskell の得意な「無限数列」を作って、必要な分だけ使い回せるようにしました。
"format" 関数は kei_q さんの投稿に使われていたものを、そのまま使わせてもらいました。

```offLine24.hs
import Data.Char
import Data.List

-- 平方数
squareNumber :: [Int]
squareNumber = [x ^ 2 | x <- [1 ..]]

-- 立方数
cubicNumber :: [Int]
cubicNumber = [x ^ 3 | x <- [1 ..]]

-- 倍数番目を撤去 (先頭が1番目であることに注意)
delNth :: Int -> [Int] -> [Int]
delNth n xs = init as ++ delNth n bs
  where (as, bs) = splitAt n xs

-- 直前を撤去
delBefore :: [Int] -> [Int] -> [Int]
delBefore (x : xs) ys
  | null as      =            delBefore xs bs
  | head bs == x = init as ++ delBefore xs bs
  | otherwise    = as      ++ delBefore xs bs
  where (as, bs) = span (< x) ys

-- 直後を撤去
delAfter :: [Int] -> [Int] -> [Int]
delAfter (x : xs) ys
  | null as      =       delAfter    xs bs
  | last as == x = as ++ delIfNextEq xs bs
  | otherwise    = as ++ delAfter    xs bs
  where
    (as, bs) = span (<= x) ys
    delIfNextEq (x : xs) (y : ys)
      | x == y    = delIfNextEq xs ys
      | otherwise = delAfter (x : xs) ys

solve :: String -> String
solve cs = format $ take 10 $ foldl f [1 ..] cs
  where
    format = intercalate "," . map show
    f ns 'S' = delAfter  squareNumber ns
    f ns 's' = delBefore squareNumber ns
    f ns 'C' = delAfter  cubicNumber  ns
    f ns 'c' = delBefore cubicNumber  ns
    f ns 'h' = drop 100 ns
    f ns c   = delNth (digitToInt c) ns


-- << Test >> --------------------------------------------------------

testData :: [(Int, String, String)]
testData =
  [(0, "ss6cc24S", "1,9,21,30,33,37,42,44,49,56"),
   (1, "h",        "101,102,103,104,105,106,107,108,109,110"),
   (2, "hh",       "201,202,203,204,205,206,207,208,209,210"),
   (3, "hhh",      "301,302,303,304,305,306,307,308,309,310"),
   (4, "2",        "1,3,5,7,9,11,13,15,17,19"),
   (5, "22",       "1,5,9,13,17,21,25,29,33,37"),
   (6, "222",      "1,9,17,25,33,41,49,57,65,73"),
   (7, "3",        "1,2,4,5,7,8,10,11,13,14"),
   (8, "33",       "1,2,5,7,10,11,14,16,19,20"),
   (9, "333",      "1,2,7,10,14,16,20,23,28,29"),
   (10, "s",       "1,2,4,5,6,7,9,10,11,12"),
   (11, "ss",      "1,4,5,6,9,10,11,12,13,16"),
   (12, "sss",     "4,5,9,10,11,12,16,17,18,19"),
   (13, "S",       "1,3,4,6,7,8,9,11,12,13"),
   (14, "SS",      "1,4,7,8,9,12,13,14,15,16"),
   (15, "SSS",     "1,8,9,13,14,15,16,20,21,22"),
   (16, "c",       "1,2,3,4,5,6,8,9,10,11"),
   (17, "cc",      "1,2,3,4,5,8,9,10,11,12"),
   (18, "ccc",     "1,2,3,4,8,9,10,11,12,13"),
   (19, "C",       "1,3,4,5,6,7,8,10,11,12"),
   (20, "CC",      "1,4,5,6,7,8,11,12,13,14"),
   (21, "CCC",     "1,5,6,7,8,12,13,14,15,16"),
   (22, "23",      "1,3,7,9,13,15,19,21,25,27"),
   (23, "32",      "1,4,7,10,13,16,19,22,25,28"),
   (24, "2h",      "201,203,205,207,209,211,213,215,217,219"),
   (25, "h2",      "101,103,105,107,109,111,113,115,117,119"),
   (26, "sC",      "1,4,5,6,7,9,10,11,12,13"),
   (27, "Cs",      "1,4,5,6,7,8,10,11,12,13"),
   (28, "s468",    "1,2,4,6,7,11,12,16,17,20"),
   (29, "S468",    "1,3,4,7,8,12,13,16,18,21"),
   (30, "cc579",   "1,2,3,4,8,9,11,13,15,16"),
   (31, "CC579",   "1,4,5,6,8,11,13,15,17,18"),
   (32, "85",      "1,2,3,4,6,7,9,10,12,13"),
   (33, "sh",      "110,111,112,113,114,115,116,117,118,119"),
   (34, "94h",     "150,151,154,155,156,158,159,160,163,164"),
   (35, "h9c8",    "101,102,103,104,105,106,107,110,111,112"),
   (36, "Cc3s",    "1,3,5,6,10,11,13,16,17,19"),
   (37, "cs4h6",   "149,150,152,153,154,157,158,160,161,162"),
   (38, "84523c",  "1,3,11,15,23,26,34,38,46,49"),
   (39, "54C78hS", "228,231,232,233,236,241,242,243,246,247"),
   (40, "65h7ccs", "151,152,153,154,157,158,160,163,164,165"),
   (41, "c95hSc2C",     "145,147,151,153,156,159,162,164,168,171"),
   (42, "c5h3Ss794",    "130,131,133,137,138,142,148,150,152,157"),
   (43, "7ShscC846",    "129,130,131,134,135,139,141,142,146,148"),
   (44, "cshSCCS7ch",   "253,254,256,259,260,261,263,264,265,266"),
   (45, "hhC7849Ss6C",  "201,202,203,205,206,211,212,216,220,225"),
   (46, "hhsc3C987Ccs", "201,202,204,205,207,208,214,217,218,220"),
   (47, "SC7S8hc59ss2", "162,169,174,178,182,185,188,194,199,203"),
   (48, "s7S6c35C9CShc",  "367,371,377,379,380,385,387,388,392,395"),
   (49, "4scC3hh982Cc5s", "422,426,430,434,447,451,459,463,471,479"),
   (50, "23h465Ssc9CchC", "1027,1033,1045,1047,1057,1069,1071,1075,1081,1093")]

test :: [(Int, Bool)]
test = map f testData
  where
    f (a, b, c) = (a, solve b == c)
```