Last active
September 12, 2016 17:40
-
-
Save rzeigler/e21cf0f1191f5fa38984 to your computer and use it in GitHub Desktop.
Translation of https://github.com/tpolecat/examples/blob/master/src/main/scala/eg/FreeMonad.scala FreeMonad example to Haskell as well as an example program.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Monad.Free | |
import Control.Monad.State.Lazy | |
data TerminalOp a = ReadLine (String -> a) | WriteLine String a | |
instance Functor TerminalOp where | |
fmap f (ReadLine g) = ReadLine (f . g) | |
fmap f (WriteLine s a) = WriteLine s (f a) | |
type TerminalIO a = Free TerminalOp a | |
readLine :: (String -> a) -> TerminalIO a | |
readLine f = liftF (ReadLine f) | |
writeLine :: String -> TerminalIO () | |
writeLine s = liftF (WriteLine s ()) | |
toIO :: TerminalOp a -> IO a | |
toIO (ReadLine f) = fmap f getLine | |
toIO (WriteLine s a) = putStrLn s >> return a | |
data TermState = TermState { stdin :: [String], stdout :: [String] } | |
toState :: TerminalOp a -> State TermState a | |
toState (ReadLine f) = do | |
stdins <- gets stdin | |
stdouts <- gets stdout | |
put (TermState (tail stdins) stdouts) | |
return $ f (head stdins) | |
toState (WriteLine s a) = do | |
stdins <- gets stdin | |
stdouts <- gets stdout | |
put (TermState stdins (s : stdouts)) | |
return a | |
countDown :: Int -> TerminalIO () | |
countDown 1 = writeLine "1" | |
countDown x = writeLine (show x) >> countDown (x - 1) | |
program :: TerminalIO () | |
program = do | |
s <- readLine read :: TerminalIO Int | |
writeLine "Tick Tock..." | |
countDown s | |
writeLine "Boom!" | |
stateProgram :: TermState -> TerminalIO a -> IO () | |
stateProgram start prog = putStrLn "Starting State: " | |
>> putStrLn ("stdin: " ++ (show (stdin start))) >> putStrLn ("stdout: " ++ (show (stdout start))) | |
>> putStrLn "Ending State: " | |
>> putStrLn ("stdin: " ++ (show (stdin end))) >> putStrLn ("stdout:" ++ (show (stdout end))) | |
where end = snd (runState sprogram start) | |
sprogram = foldFree toState prog | |
main :: IO () | |
main = putStrLn "Enter a number: " | |
>> (foldFree toIO program) | |
>> stateProgram (TermState ["2"] []) program |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment