import Data.List (group)
import Control.Monad (forM_)

replicateAtLeastOne :: Int -> a -> [a]
replicateAtLeastOne n x = x: replicate (n-1) x

zipWithLazy :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWithLazy f ~(x:xs) ~(y:ys) = f x y: zipWithLazy f xs ys

kolakoski :: [Int] -> [Int]
kolakoski items = s
  where s = concat $ zipWithLazy replicateAtLeastOne s $ cycle items

rle :: Eq a => [a] -> [Int]
rle = map length . group

sameAsRleUpTo :: Int -> [Int] -> Bool
sameAsRleUpTo n s = r == take (length r) prefix
  where prefix = take n s
        r = init $ rle prefix

main :: IO ()
main = forM_ [([1, 2], 20),
              ([2, 1], 20), 
              ([1, 3, 1, 2], 30),
              ([1, 3, 2, 1], 30)]
        $ \(items, n) -> do
          putStrLn $ "First " ++ show n ++ " members of the sequence generated by " ++ show items ++ ":"
          let s = kolakoski items
          print $ take n s
          putStrLn $ "Possible Kolakoski sequence? " ++ show (sameAsRleUpTo n s)
          putStrLn ""