import Data.Array
import Data.List
import Data.Monoid
import Data.Maybe
import Control.Monad.Fix
import Control.Monad
import Control.Monad.Cont
import Data.IORef
main1 :: IO ()
main1 = fizzbuzz 1 100
makeLabel :: (MonadCont m) => m (m a)
makeLabel = callCC (\k -> return (fix k))
makeLabelArg :: (MonadCont m) => t -> m (t -> m b, t)
makeLabelArg a = callCC (\k -> return (fix (curry k),a))
fizzbuzz a b = flip runContT return $ callCC $ \exit -> let break = exit () in do
v <- io (newIORef a)
continue <- makeLabel
x <- io (readIORef v)
when (x > b) (break)
io (writeIORef v (x+1))
when (x `mod` 15 == 0) $ io (putStrLn "FizzBuzz") >> continue
when (x `mod` 3 == 0) $ io (putStrLn "Fizz") >> continue
when (x `mod` 5 == 0) $ io (putStrLn "Buzz") >> continue
io (print x)
continue
where io = liftIO
main2 :: IO ()
main2 = putStr . unlines $ fizzbuzzFromTo 1 100
main3 :: IO ()
main3 = putStr . unlines $ map fizzbuzzAt [1..100]
data Msg a = Msg { msgPeriod :: Int
, msgs :: [Maybe a]
} deriving Show
msg i s | i < 1 = error "Need Postive cycle length"
| otherwise = Msg i (Just s : replicate (pred i) Nothing)
instance Monoid a => Monoid (Msg a) where
mempty = Msg 1 [Nothing]
mappend (Msg i xs) (Msg j ys) = let k = lcm i j
f Nothing Nothing = Nothing
f a b = Just $ (fromMaybe mempty a) `mappend` (fromMaybe mempty b)
zs = take k $ zipWith f (cycle xs) (cycle ys)
in Msg k zs
mconcat [] = mempty
mconcat [x] = x
mconcat xs = let k = foldl' lcm 1 . map msgPeriod $ xs
f [] = Nothing
f ms = Just (mconcat ms)
zs = take k $ map (f . catMaybes) (transpose . map (cycle . msgs) $ xs)
in Msg k zs
fizzbuzzFromTo :: Int -> Int -> [String]
fizzbuzzFromTo a b = zipWith ($) toApply [a..b]
where toApply = drop (a `mod` k) composed
(Msg k xs) = (msg 3 "Fizz") `mappend` (msg 5 "Buzz")
composed :: [Int->String]
composed = cycle $ map (maybe show const) xs
fizzbuzzAt :: Int -> String
fizzbuzzAt x = (composed ! mod x k) x
where (Msg k xs) = (msg 3 "Fizz") `mappend` (msg 5 "Buzz")
composed :: Array Int (Int->String)
composed = listArray (0,pred k) . map (maybe show const) $ xs