Haskell MTL / трансформаторы эквивалентно масштабированию состояния объектива - PullRequest
0 голосов
/ 08 февраля 2019

Я работаю над веб-приложением на основе мисо и пытаюсь обернуть модель (состояние) 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 Ответ

0 голосов
/ 08 февраля 2019

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)
...