Open yaitskov opened 2 years ago
local
comes from the traditional Reader
monads local so searching for that might yield more resources. I'm not aware of interpretations other than that one.
In the traditional Reader
, local
is implemented by post-composing a function with our "Reader environment":
> runReader ask 5
5
> runReader (local succ ask) 5
6
> runReader ask [1,2]
[1,2]
> runReader (local (4:) ask) [1,2]
[4,1,2]
> runReader (local (4:) (asks (42:))) [1,2]
[42,4,1,2]
It's applicable when you want to use a "state-like" effect, but you don't care about the state persisting after your action runs. My go-to examples are getting the depth of a tree in a contrived/overcomplicated way:
import Control.Monad.Trans.Reader
data Tree a
= Empty
| Node (Tree a) a (Tree a)
depth :: Tree a -> Int
depth t = runReader (go t) 0
where
go :: Tree a -> Reader Int Int
go Empty = ask
go (Node l _ r) = do
l' <- local succ $ go l
-- note how we also need to local succ for the right subtree,
-- because the succ from above doesn't "carry over" to here
r' <- local succ $ go r
pure $ max l' r'
and working with nameless lambda terms, where when you enter a lambda, you want to shift all the variables inside the body of the lambda up by one (in a similar manner with something like local succ
again).
I think the takeaway of this might be that we should include documentation for effects even if they're just replications of common functionality from base
How to use
local
function? Googling was also not sufficient.