Reputation: 63
I'm working on a miso-based webapp and I'm trying to wrap the model (state) of a Transition Action InnerModel ()
into a Transition Action ModelWrapper ()
where
type Miso.Transition action model = StateT model (Writer [Sub action])
and data ModelWrapper = ClientModel Clients.Model | ...
unfortunately I can't seem to find a way to modify the state's type, or am not sure at all what I have to do.
The documentation shows how to do deal mostly with the lens library. So far I've adapted things like .=
into Control.Monad.State.modify
, but I can't find an equivalent to zoom
, which I need to for running a computation with the unwrapped model as state.
I've tried all of the following with no luck. the closest i got was with execStateT, but I couldn't keep the actions so it was useless.
The code below has my different attempts to tackle it and may provide some context.
updateModel ::
Action ->
Transition Action ModelWrapper ()
updateModel ac = case ac of
--ShowSection sect -> modify $ \mo -> mo{currentSection=sect}
--UpdateSubmodel submo -> modify $ \mo -> mo{sectionModel=submo}
UpdateSubmodel submo -> put submo
SectionAct sact -> case sact of
ActionClients clac -> do
gets $ \(ModelClients mo) -> mo
(Clients.updateModel sectionPipeback clac)
--return ()
--gets (\(ModelClients mo) -> mo)
--modify ModelClients
--modify $ \mo -> ModelClients mo
--ModelClients mo <- get
--let trans = (Clients.updateModel sectionPipeback clac)
-- w = execStateT trans mo
--put $ ModelClients mo
--let (clmo, acts) = runWriter $ execStateT trans mo
--let w = execStateT trans mo
--StateT (ModelClients $ execWriter w) w ()
--StateT (\ins -> writer )
--execStateT trans mo
--execStateT trans mo
--let (clmo, acts) = runWriter $ execStateT trans mo
--clmo <- lift $ execStateT trans mo
--put $ ModelClients clmo
--lift $ acts
--pure acts
--pure $ SeictionAct a
NoOp -> return ()
Upvotes: 2
Views: 236
Reputation: 31335
zoom
from lens
is convenient because it uses a lens
to capture both a getter and setter at the same time. But without a lens
, you can explicitly deal with a getter and setter and do the same thing. Adding the imports:
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
You can then implement a zoom
-like function:
zoomy
:: Monad m
=> (outer -> inner) -- ^ getter
-> (inner -> outer -> outer) -- ^ setter
-> StateT inner m a
-> StateT outer m a
zoomy getter setter action = do
origOuter <- get
(a, newInner) <- lift $ runStateT action (getter origOuter)
let newOuter = setter newInner origOuter
put newOuter
pure a
Or, if you want to play directly with the data constructors:
zoomier
:: Monad m
=> (outer -> inner) -- ^ getter
-> (inner -> outer -> outer) -- ^ setter
-> StateT inner m a
-> StateT outer m a
zoomier getter setter (StateT action) = StateT $ \origOuter -> do
(a, newInner) <- action (getter origOuter)
let newOuter = setter newInner origOuter
pure (a, newOuter)
Upvotes: 2