Skip to content

Commit

Permalink
WIP on reader/state.
Browse files Browse the repository at this point in the history
  • Loading branch information
athas committed Aug 8, 2024
1 parent ae8da91 commit 93b672a
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 0 deletions.
84 changes: 84 additions & 0 deletions haskell/readerstate.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
module ReaderState where

import Control.Monad (ap, liftM)

-- ANCHOR: Reader
newtype Reader env a = Reader (env -> a)

-- ANCHOR_END: Reader

-- ANCHOR: Functor_Reader
instance Functor (Reader env) where
fmap = liftM

-- ANCHOR_END: Functor_Reader

-- ANCHOR: Applicative_Reader
instance Applicative (Reader env) where
pure x = Reader $ \_env -> x
(<*>) = ap

-- ANCHOR_END: Applicative_Reader

-- ANCHOR: Monad_Reader
instance Monad (Reader env) where
Reader m >>= f = Reader $ \env ->
let x = m env
Reader f' = f x
in f' env

-- ANCHOR_END: Monad_State

-- ANCHOR: State
newtype State s a = State (s -> (a, s))

-- ANCHOR_END: State

-- ANCHOR: Functor_State
instance Functor (State env) where
fmap = liftM

-- ANCHOR_END: Functor_State

-- ANCHOR: Applicative_State
instance Applicative (State env) where
pure x = State $ \state -> (x, state)
(<*>) = ap

-- ANCHOR_END: Applicative_State

-- ANCHOR: Monad_State
instance Monad (State env) where
State m >>= f = State $ \state ->
let (x, state') = m state
State f' = f x
in f' state'

-- ANCHOR_END: Monad_State

-- ANCHOR: RS
newtype RS env s a = RS (env -> s -> (a, s))

-- ANCHOR_END: RS

-- ANCHOR: Functor_RS
instance Functor (RS env s) where
fmap = liftM

-- ANCHOR_END: Functor_RS

-- ANCHOR: Applicative_RS
instance Applicative (RS env s) where
pure x = RS $ \_env state -> (x, state)
(<*>) = ap

-- ANCHOR_END: Applicative_RS

-- ANCHOR: Monad_RS
instance Monad (RS env s) where
RS m >>= f = RS $ \env state ->
let (x, state') = m env state
RS f' = f x
in f' env state'

-- ANCHOR_END: Monad_RS
66 changes: 66 additions & 0 deletions src/chapter_2.md
Original file line number Diff line number Diff line change
@@ -1 +1,67 @@
# Monads

## The Reader Monad

```Haskell
{{#include ../haskell/readerstate.hs:Reader}}
```

```Haskell
{{#include ../haskell/readerstate.hs:Monad_Reader}}
```

```Haskell
{{#include ../haskell/readerstate.hs:Functor_Reader}}
{{#include ../haskell/readerstate.hs:Applicative_Reader}}
```

## The State Monad

```Haskell
{{#include ../haskell/readerstate.hs:State}}
```

```Haskell
{{#include ../haskell/readerstate.hs:Monad_State}}
```

```Haskell
{{#include ../haskell/readerstate.hs:Functor_State}}
{{#include ../haskell/readerstate.hs:Applicative_State}}
```

## Combining Reader and State

One limitation of monads - in particular the simple form we study in
AP - is that they do not compose well. We cannot in general take two
monads, such as `Reader` and `State`, and combine them into a single
monad that supports both of their functionalities. There are
techniques that allow for this, such as *monad transformers*, but they
are somewhat complex and outside the scope of AP. Instead, if we wish
to have a monad that supports both a read-only environment (such as
with `Reader`) and a mutable store (such as with `State`), then we
must write a monad from scratch, such as the following `RS` monad.

```Haskell
{{#include ../haskell/readerstate.hs:RS}}
```

See how the function we use to represent the monad takes two
arguments, `env` and `s`, corresponding to the environment and store
respectively, but returns only a new store.

The `Monad` instance itself is a little intricate, but it just
combines the dataflow that we also saw for the `Reader` and `State`
monads above:

```Haskell
{{#include ../haskell/readerstate.hs:Monad_RS}}
```

The `Functor` and `Applicative` instances are then just the usual
boilerplate.

```Haskell
{{#include ../haskell/readerstate.hs:Functor_RS}}
{{#include ../haskell/readerstate.hs:Applicative_RS}}
```

0 comments on commit 93b672a

Please sign in to comment.