Haskell MTL / трансформаторы эквивалентно масштабированию состояния объектива
Я работаю над веб-приложением на основе мисо и пытаюсь обернуть модель (состояние) Transition Action InnerModel ()
в Transition Action ModelWrapper ()
где
type Miso.Transition action model = StateT model (Writer [Sub action])
а также data ModelWrapper = ClientModel Clients.Model | ...
К сожалению, я не могу найти способ изменить тип штата или не совсем уверен, что мне делать.
Документация показывает, как работать с библиотекой линз. До сих пор я адаптировал такие вещи, как .=
в Control.Monad.State.modify
, но я не могу найти эквивалент zoom
, что мне нужно для запуска вычислений с развернутой моделью в качестве состояния.
Я попробовал все следующее без удачи. ближе всего я был с execStateT, но я не мог сохранить действия, так что это было бесполезно.
Приведенный ниже код содержит мои различные попытки справиться с этим и может предоставить некоторый контекст.
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 ()
1 ответ
zoom
от lens
это удобно, потому что он использует lens
захватить и геттер и сеттер одновременно. Но без lens
Вы можете явно иметь дело с геттером и сеттером и делать то же самое. Добавление импорта:
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
Затем вы можете реализовать zoom
-подобная функция:
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
Или, если вы хотите играть непосредственно с конструкторами данных:
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)