# Purifying Code with Algebra

September 16, 2016

# Motivation

Side effects are the worst.

``````getNum :: IO Int
getNum = do
removeDirectoryRecursive "/"
return 42``````

# Objective

Use a GADT to get `IO` out of function types.

``{-# LANGUAGE GADTs #-}``

# Side effects and `IO`

A function might have side effects if it uses the `IO` type class.

# `IO` with a side effect

``````getNum2 :: IO Int

Returns whatever value the user feels like providing

# `IO` without a side effect

``````getNum3 :: IO Int
getNum3 = return 42``````

Always returns 42

# Side effects and `IO`

A function can't have side effects if it doesn't use `IO`.

# A side effect without `IO`

``````getNum4 :: Int

This will not compile

# Basic console IO

• `getLine :: IO String`
• `putStr :: String -> IO ()`

# `LameCalc`

``````calculator :: IO ()
calculator = do
putStr "Enter a number: "
x <- getLine
putStr "Enter another one: "
y <- getLine
putStr \$ x ++ " * " ++ y ++ " = " ++ z ++ "\n"``````

# Abstract the effects

``````data ConsoleIO a where
PutStr :: String -> ConsoleIO ()
GetLine :: ConsoleIO String``````

# Combinators as data types

``````data ConsoleIO a where
PutStr :: String -> ConsoleIO ()
GetLine :: ConsoleIO String``````
``````  Pure :: a -> ConsoleIO a
Ap :: ConsoleIO (a -> b) -> ConsoleIO a -> ConsoleIO b
Bind :: ConsoleIO a -> (a -> ConsoleIO b) -> ConsoleIO b``````

# Combinators as instances

``````instance Functor ConsoleIO where
fmap f s = Bind s (\a -> Pure \$ f a)

instance Applicative ConsoleIO where
pure a = Pure a
(<*>) f a = Ap f a

(>>=) a mb = Bind a mb``````

# Interpret the effects

``````class Effect x where
runEffect :: x a -> IO a

instance Effect ConsoleIO where
runEffect (Pure a) = return a
runEffect (Ap f a) = (runEffect f) <*> (runEffect a)
runEffect (Bind s fs) = (runEffect s) >>= (\a -> runEffect (fs a))
runEffect (PutStr s) = putStr s
runEffect GetLine = getLine``````

# Purify `calculator`

``````calculator1 :: IO ()
calculator1 = do
putStr "Enter a number: "
x <- getLine
putStr "Enter another one: "
y <- getLine
putStr \$ x ++ " * " ++ y ++ " = " ++ z ++ "\n"``````

# `PureCalc`

``````calculator2 :: ConsoleIO ()
calculator2 = do
PutStr "Enter a number: "
x <- GetLine
PutStr "Enter another one: "
y <- GetLine
PutStr \$ x ++ " * " ++ y ++ " = " ++ z ++ "\n"``````

Looks just like `calculator1`, but doesn't allow for side effects

# Demo

``````main :: IO ()
main = do
putStr "\nRunning calculator...\n"
calculator
putStr "\nRunning calculator2...\n"
runEffect calculator2``````

# Usage

These slides are literate Haskell. Try running them with Codedown:

``````\$ curl https://earldouglas.com/talks/gadt-io/slides.md | codedown haskell > gadt-io.hs