import Control.Monad (forM_) import Control.Monad.State import Data.List (group) {- -- With typeclasses class Widget a where click :: a -> a render :: a -> String newtype Counter = Counter Integer instance Widget Counter where click (Counter n) = Counter (n + 1) render (Counter n) = show n newtype LookAndSay = LookAndSay String instance Widget LookAndSay where click (LookAndSay s) = LookAndSay $ concatMap (\x -> show (length x) ++ take 1 x) $ group s render (LookAndSay s) = s data SomeWidget = forall a . Widget a => SomeWidget a instance Widget SomeWidget where click (SomeWidget x) = SomeWidget (click x) render (SomeWidget x) = render x main :: IO () main = (`evalStateT` [SomeWidget (Counter 1), SomeWidget (Counter 42), SomeWidget (LookAndSay "1")]) $ do forM_ [1..10] $ \_ -> do get >>= mapM_ (liftIO . putStrLn . render) liftIO $ putChar '\n' modify (map click) -} -- Without type classes or polymorphism, just closures data Widget = Widget { click :: Widget, render :: String } counter :: Integer -> Widget counter n = Widget (counter (n+1)) (show n) lookAndSay :: Widget lookAndSay = go "1" where go s = Widget (go $ concatMap (\x -> show (length x) ++ take 1 x) $ group s) s typeChangingWidget :: Integer -> Integer -> Widget typeChangingWidget m n | m <= 0 = counter 0 | otherwise = Widget (typeChangingWidget (m-n) n) (show m) pair :: Widget -> Widget -> Widget pair x y = Widget (pair (click x) (click y)) (render x ++ "," ++ render y) doubled :: Widget -> Widget doubled x = Widget (doubled (click (click x))) (render x) main :: IO () main = (`evalStateT` [counter 1, typeChangingWidget 5 2, lookAndSay, pair (doubled (counter 0)) (counter 0)]) $ do forM_ [1..10] $ \_ -> do get >>= mapM_ (liftIO . putStrLn . render) liftIO $ putChar '\n' modify (map click)