Skip to content

Instantly share code, notes, and snippets.

@roboguy13
Last active January 8, 2025 03:34
Show Gist options
  • Save roboguy13/f2643d4f67ccc799790f1ca9ce6e0422 to your computer and use it in GitHub Desktop.
Save roboguy13/f2643d4f67ccc799790f1ca9ce6e0422 to your computer and use it in GitHub Desktop.
{-# LANGUAGE GADTs #-}
import Control.Monad
-- Note that Cmd values are perfectly "pure" values. There's nothing here that
-- makes them impure.
data Cmd a where
PutStr :: String -> Cmd ()
PutStrLn :: String -> Cmd ()
ReadLn :: Cmd Int
Pure :: a -> Cmd a
Bind :: Cmd a -> (a -> Cmd b) -> Cmd b
instance Functor Cmd where
fmap f x = x >>= pure . f
instance Applicative Cmd where
pure = Pure
(<*>) = ap
instance Monad Cmd where
return = pure
(>>=) = Bind
-- This is a Cmd, which is a perfectly pure value
example :: Cmd ()
example = do
PutStr "Enter a number: "
a <- ReadLn
PutStr "Enter another number: "
b <- ReadLn
let c = a + b
PutStrLn $ "first + second = " ++ show c
if c < 10
then PutStrLn "This is less than 10"
else PutStrLn "This is greater than or equal to 10"
main :: IO ()
main = run example
--
-- Interpret as IO. We could interpret this in other ways too!
--
run :: Cmd a -> IO a
run (PutStr s) = putStr s
run (PutStrLn s) = putStrLn s
run ReadLn = readLn
run (Pure x) = pure x
run (Bind m f) = do
x <- run m
run (f x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment