【问题标题】:How to manage internal state in a Haskell modular application?如何在 Haskell 模块化应用程序中管理内部状态?
【发布时间】:2020-06-16 00:22:58
【问题描述】:

我正在遵循 on this video by Ben Kolera 提出的构建模块化 Haskell 应用程序的建议。

建议使用多个 monad 转换器,以使应用程序模块化和组织化。建议使用自定义 liftModule 函数将这些 monad 组合在一起。

例如,我们有一个主要的App 模块和一个Logic 模块。

newtype App a = App
  { unApp :: ExceptT AppError (ReaderT AppEnv IO) a }

newtype Logic a = Logic
  { unLogic :: ExceptT LogicError (Reader LogicEnv) a }

liftLogic 定义如下。

runLogic :: LogicEnv -> Logic a -> Either LogicError a

liftLogic :: Logic a -> App a
liftLogic l = do 
  c <- asks appEnvLogic
  either (throwError . AppLogicError) pure $ runLogic c l

使用这种方法,我如何给模块一个内部状态?如果我将StateT LogicState 放入Logic 变压器,那么liftMonad 不会完全运行monad,从而解开它并破坏它的内部状态?

我看到的唯一方法是将Logic 的内部状态泄露给App,我认为这是反模块化,因为它迫使App 处理Logic 的状态。

【问题讨论】:

  • 我认为在这里更具体地了解细节会有所帮助。也许您可以在代码中勾勒出您正在考虑的内容,给出一些假设的类型签名以及您看到问题浮出水面的方式。
  • 我想stackoverflow.com/questions/4785379/… 是我在这里要问的。我喜欢这个问题的答案。

标签: haskell monads monad-transformers


【解决方案1】:

在你的例子中,App 已经“照顾”了LogicEnvLogicError,所以我认为反模块化的船已经航行了。

无论如何,要在App 中运行有状态的Logic,您需要从某个地方获取初始LogicState,并在Logic 操作完成后决定如何处理它。特别是,如果您希望能够将两个 Logic 动作分别提升到 App 并让它们线程化 LogicState,那么 App 也需要是有状态的,LogicState 埋在AppState.

所以,答案大概是这样的:

newtype App a = App
  { unApp :: ExceptT AppError (StateT AppState (ReaderT AppEnv IO)) a }
  deriving (Functor, Applicative, Monad, MonadReader AppEnv, 
            MonadState AppState, MonadError AppError)

newtype Logic a = Logic
  { unLogic :: ExceptT LogicError (StateT LogicState (Reader LogicEnv)) a }

runLogic :: Logic a -> LogicEnv -> LogicState -> (Either LogicError a, LogicState)
runLogic l c s = runReader (runStateT (runExceptT (unLogic l)) s) c

liftLogic :: Logic a -> App a
liftLogic l = do
  c <- asks appEnvLogic
  s <- get
  let (ea, ls') = runLogic l c (logicState s)
  put s { logicState = ls' }
  either (throwError . AppLogicError) return ea

请注意,App 可能对 LogicState 内部结构一无所知。只是不要导出LogicState 的构造函数。然后,App 不能对LogicState 做任何事情,只能代表Logic 维护它。当然,你必须安排从Logic 导出一些函数来获得初始的LogicState

【讨论】:

    猜你喜欢
    • 2015-10-13
    • 1970-01-01
    • 2012-08-26
    • 2018-09-04
    • 1970-01-01
    • 2013-09-16
    • 1970-01-01
    • 2020-12-26
    • 1970-01-01
    相关资源
    最近更新 更多