haskell mtl / transformers相当于镜头的缩放状态

时间:2019-02-07 23:22:09

标签: haskell lens

我正在研究基于味o的Web应用程序,并且试图将Transition Action InnerModel ()的模型(状态)包装到Transition Action ModelWrapper ()中,其中

type Miso.Transition action model = StateT model (Writer [Sub action])

data ModelWrapper = ClientModel Clients.Model | ...

不幸的是,我似乎找不到改变状态类型的方法,或者根本不确定我该怎么做。

documentation显示了如何处理镜头库。到目前为止,我已经将.=之类的内容改编成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 个答案:

答案 0 :(得分:1)

zoom中的

lens很方便,因为它使用lens来同时捕获一个getter和setter。但是,如果没有lens,则可以显式处理getter和setter并执行相同的操作。添加导入:

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)