data FizzBuzz = Numero Int | Fizz | Buzz | FizzBuzz instance Show FizzBuzz where show (Numero x) = show x show Fizz = "Fizz" show Buzz = "Buzz" show FizzBuzz = "FizzBuzz" type Max = Int type Current = Int data Counter = Counter { max :: Max , current :: Current } deriving (Show, Eq) class Next n where next :: n -> n counter :: Max -> Counter counter m = Counter m 1 instance Next Counter where next ct@(Counter m c) | match ct = Counter m 1 | otherwise = Counter m (c + 1) match :: Counter -> Bool match (Counter m c) | m == c = True | otherwise = False data Runner = Runner Counter Counter Counter instance Next Runner where next (Runner i f b) = Runner (next i) (next f) (next b) runner :: Int -> Runner runner m = Runner (counter m) (counter 3) (counter 5) fin :: Runner -> Bool fin (Runner i _ _) = match i run :: Runner -> [FizzBuzz] run r | fin r = [fizzbuzz r] | otherwise = (fizzbuzz r) : (run $ next r) fizzbuzz :: Runner -> FizzBuzz fizzbuzz (Runner i f b) = case (match f, match b) of (True, True) -> FizzBuzz (False, True) -> Buzz (True, False) -> Fizz (_, _) -> Numero $ current i readInput :: IO String -> IO Int readInput io = fmap read io showResult :: [FizzBuzz] -> IO () showResult = mapM_ print app :: IO String -> IO () app io = do s <- readInput io r <- return $ runner s r' <- return $ run r showResult r' main :: IO () main = app getLine