James Earl Douglas

September 16, 2016

Side effects are the worst.

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

Use a GADT to get `IO`

out of function types.

`{-# LANGUAGE GADTs #-}`

`IO`

A function *might* have side effects if it uses the `IO`

type class.

`IO`

with a side effect```
getNum2 :: IO Int
getNum2 = read <$> getLine
```

*Returns whatever value the user feels like providing*

`IO`

without a side effect```
getNum3 :: IO Int
getNum3 = return 42
```

*Always returns 42*

`IO`

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

.

`IO`

```
getNum4 :: Int
getNum4 = read <$> getLine
```

*This will not compile*

Let's start with a couple of library functions:

`getLine :: IO String`

`putStr :: String -> IO ()`

`LameCalc`

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

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

```
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
```

```
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
instance Monad ConsoleIO where
(>>=) a mb = Bind a mb
```

```
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
```

`calculator`

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

`PureCalc`

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

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

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

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

```
$ curl -s https://earldouglas.com/talks/gadt-io/slides.md | codedown haskell > gadt-io.hs
$ runhaskell gadt-io.hs
Running calculator...
Enter a number: 6
Enter another one: 7
6 * 7 = 42
Running calculator2...
Enter a number: 6
Enter another one: 7
6 * 7 = 42
```