【问题标题】:How to kickstart monad transformer stack from main?如何从主启动单子变压器堆栈?
【发布时间】:2016-08-12 09:27:41
【问题描述】:

这是我上一个问题的后续问题:State and IO Monads

我的目标是为文件创建一个简单的文本编辑器。我已经有一个Editor 组件,它很好地封装了底层数据结构上的所有编辑操作。

感谢我之前的问题的答案,我能够重构我的程序,以便我现在拥有一个不错的 monad 转换器堆栈:

type Session = StateT AppState (StateT Editor IO)

AppState 保存应用程序的全局状态(当前打开的文件等),而Editor 表示应用程序编辑组件的内部状态(插入符号所在的位置等)。 .)。我有一个函数是应用程序的主要驱动程序:

eventLoop :: Session ()

到目前为止一切顺利,但是现在我不知道如何从我的main 函数中实际启动我的转换器堆栈? Main 必须在 IO monad 中返回一些东西,它位于我的堆栈的最底部。我的猜测是我必须初始化我的AppState,然后执行以下操作:

main = do
  let initialAppState = ...
  return $ runStateT eventLoop initialAppState

但是我现在在哪里初始化我的Editor

主要让我困惑的是,在重构之前,Editor 只是AppState 的成员:

data AppState = { editor :: Editor , ... }

但现在它已从AppState 中移出,并在某种程度上成为变压器堆栈上的兄弟姐妹。 Editor 不应该仍然是AppState 的一部分,因为修改它意味着修改整体状态?

如何使用AppStateEditor 正确初始化我的Session,然后从我的main 运行它?

【问题讨论】:

  • StateT 包裹在StateT 内将需要笨拙的电梯组合才能访问正确的状态。 imo 最好只使用StateT (AppState, EditorState)(或您自己的数据类型),这样您就可以使用MonadStateget 等而无需提升。

标签: haskell monads monad-transformers state-monad


【解决方案1】:

我如何才能真正从我的主函数启动我的转换器堆栈?

main =
  flip evalStateT initialAppState $
  flip evalStateT initialEditorState $
  eventLoop
  where
    initialAppState =
      error "Define me"
    initialEditorState =
      error "Define me"

Editor 不应该仍然是 AppState 的一部分,因为修改它意味着修改整体状态吗?

视情况而定。

还记得 Monad Transformer 的目的是以特别的方式扩展功能吗?临时我的意思是,不重写现有的代码库,而是通过添加它。因此,如果您已经拥有 Editor 和 AppState 的独立 API,则使用转换器堆栈将它们组合到另一个“dome”模块中会更容易。

OTOH,从初始架构的角度来看,AppState 是一个包含 Editor(我将其命名为 EditorState)等内容的数据结构是完全有道理的。在这种情况下,AppState 的 API 应该封装 Editor 的 API。 “镜头”库将帮助您处理这种复合数据结构(尽管我必须提到它有一个陡峭的学习曲线)。

【讨论】:

  • 又是你 :) 谢谢,在你的帮助下,我一切顺利。我之前已经使用过一次镜头,但我从来没有真正理解过这个概念,我想在下次尝试这个话题时放慢速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多