Search code examples
haskellfunctional-programminghaskell-lens

Lift state monad to focus on part of a record


With the following code snippet:

data Circle = Circle 
            { center :: Point
            , radius :: Double
            }

data Point = Point (Double, Double)

someFuncOverPoint :: State Point blahblah

I wonder if there is a function that can make the someFuncOverPoint to focus on Circle:

someMagicFunc :: ??? -> State Point blahblah -> State Circle blahblah

Maybe this can be implemented using lens?


Solution

  • Strictly speaking you can. Indeed, we can create a state by first generating the first State Point a, and then pass that into a State, so:

    someMagicFunc :: Double -> State Point a -> State Circle a
    someMagicFunc r s = State (\s0 -> let ~(s1, a) = runState s s0 in (Circle s1 r, a))

    So here we construct a State that works with a function that maps the initial state s0 to the next state s1 and the result, and then we turn that into a 2-tuple with the Circle as state, and the "result" a as well.

    That being said, it is a bit strange to change the type of the state. Usually the type of the state remains the same over all the actions.