Skip to content

Instantly share code, notes, and snippets.

@relrod
Created January 12, 2016 21:59
Show Gist options
  • Save relrod/f15adcec3021221d2d74 to your computer and use it in GitHub Desktop.
Save relrod/f15adcec3021221d2d74 to your computer and use it in GitHub Desktop.
What is the practical difference?
module Approach1 where
import Control.Applicative
import Control.Monad
import Prelude (Functor, Char, fmap, (.), IO)
import qualified Prelude
data IOOperation a =
PutChar Char a
| GetChar (Char -> a)
instance Functor IOOperation where
fmap f (PutChar c a) = PutChar c (f a)
fmap f (GetChar g) = GetChar (f . g)
data FreeIO a =
Done a
| More (IOOperation (FreeIO a))
instance Functor FreeIO where
fmap f (Done a) = Done (f a)
fmap f (More a) = More (fmap (fmap f) a)
instance Applicative FreeIO where
pure = return
(<*>) = ap
instance Monad FreeIO where
Done a >>= f = f a
More a >>= f = More (fmap (>>= f) a)
putChar :: Char -> FreeIO ()
putChar c = More (PutChar c (Done ()))
getChar :: FreeIO Char
getChar = More (GetChar Done)
-- Natural transformation: FreeIO a ~> IO a
unsafePerformFreeIO :: FreeIO a -> IO a
unsafePerformFreeIO (Done a) = return a
unsafePerformFreeIO (More a) =
case a of
PutChar c next -> Prelude.putChar c >> unsafePerformFreeIO next
GetChar f -> Prelude.getChar >>= unsafePerformFreeIO . f
demo :: FreeIO ()
demo = mapM_ putChar "hello world!"
module Approach2 where
import Control.Applicative
import Control.Monad
import Prelude (Functor, Char, fmap, (.), IO)
import qualified Prelude
data IOOperation a =
PutChar Char (IOOperation a)
| GetChar (Char -> IOOperation a)
| Return a
instance Functor IOOperation where
fmap f (PutChar c a) = PutChar c (fmap f a)
fmap f (GetChar g) = GetChar (fmap f . g)
fmap f (Return a) = Return (f a)
instance Applicative IOOperation where
pure = return
(<*>) = ap
instance Monad IOOperation where
return = Return
Return a >>= f = f a
PutChar c n >>= f = PutChar c (n >>= f)
GetChar f >>= g = GetChar (\x -> f x >>= g)
getChar :: IOOperation Char
getChar = GetChar Return
putChar :: Char -> IOOperation ()
putChar c = PutChar c (Return ())
-- Natural transformation: IOOperation a ~> IO a
unsafePerformFreeIO :: IOOperation a -> IO a
unsafePerformFreeIO (Return a) = return a
unsafePerformFreeIO (GetChar f) = Prelude.getChar >>= unsafePerformFreeIO . f
unsafePerformFreeIO (PutChar a io) = Prelude.putChar a >> unsafePerformFreeIO io
demo :: IOOperation ()
demo = mapM_ putChar "hello world!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment