如何从 main 启动 monad 转换器堆栈?
How to kickstart monad transformer stack from main?
这是我上一个问题的后续问题:
我的目标是为文件创建一个简单的文本编辑器。我已经有了一个 Editor
组件,它很好地封装了对底层数据结构的所有编辑操作。
感谢我之前问题的答案,我能够重构我的程序,这样我现在就有了一个不错的 monad 转换器堆栈:
type Session = StateT AppState (StateT Editor IO)
AppState
保存应用程序的全局状态(当前打开的文件等),而 Editor
表示应用程序编辑组件的内部状态(其中插入符是在,等等...)。我有一个函数是应用程序的主要驱动程序:
eventLoop :: Session ()
到目前为止一切顺利,但是现在我不知道如何从我的 main
函数中实际启动我的转换器堆栈? Main 必须 return IO
monad 中的某些东西,它位于我的堆栈的最底部。我的猜测是我必须初始化我的 AppState
然后执行类似的操作:
main = do
let initialAppState = ...
return $ runStateT eventLoop initialAppState
但是我现在在哪里初始化我的 Editor
?
最让我困惑的是,在重构之前,Editor
只是 AppState
:
的成员
data AppState = { editor :: Editor , ... }
但现在它已经从 AppState
中移出,并且在某种程度上成为了转换器堆栈中的同级。 Editor
不应该仍然是 AppState
的一部分,因为修改它意味着修改整体状态吗?
如何使用 AppState
和 Editor
正确初始化我的 Session
,然后从我的 main
中初始化 运行?
how I can actually kick-start my transformer stack from my main function?
main =
flip evalStateT initialAppState $
flip evalStateT initialEditorState $
eventLoop
where
initialAppState =
error "Define me"
initialEditorState =
error "Define me"
Shouldn't Editor still be part of AppState because modifying it means modifying the overall state?
视情况而定。
还记得 Monad Transformer 的目的是以临时方式扩展功能吗?我的意思是临时的,不重写现有的代码库,而是通过添加到它。因此,如果您已经隔离了 API 的 Editor 和 AppState,则使用转换器堆栈将它们组合到另一个 "dome" 模块中会更容易。
OTOH,从初始架构的角度来看,AppState 是一个包含 Editor(我将其命名为 EditorState)等内容的数据结构是完全有道理的。在这种情况下,AppState 的API 应该封装Editor 的API。 "lens" 库将帮助您处理此类复合数据结构(尽管我必须提到它的学习曲线很陡)。
这是我上一个问题的后续问题:
我的目标是为文件创建一个简单的文本编辑器。我已经有了一个 Editor
组件,它很好地封装了对底层数据结构的所有编辑操作。
感谢我之前问题的答案,我能够重构我的程序,这样我现在就有了一个不错的 monad 转换器堆栈:
type Session = StateT AppState (StateT Editor IO)
AppState
保存应用程序的全局状态(当前打开的文件等),而 Editor
表示应用程序编辑组件的内部状态(其中插入符是在,等等...)。我有一个函数是应用程序的主要驱动程序:
eventLoop :: Session ()
到目前为止一切顺利,但是现在我不知道如何从我的 main
函数中实际启动我的转换器堆栈? Main 必须 return IO
monad 中的某些东西,它位于我的堆栈的最底部。我的猜测是我必须初始化我的 AppState
然后执行类似的操作:
main = do
let initialAppState = ...
return $ runStateT eventLoop initialAppState
但是我现在在哪里初始化我的 Editor
?
最让我困惑的是,在重构之前,Editor
只是 AppState
:
data AppState = { editor :: Editor , ... }
但现在它已经从 AppState
中移出,并且在某种程度上成为了转换器堆栈中的同级。 Editor
不应该仍然是 AppState
的一部分,因为修改它意味着修改整体状态吗?
如何使用 AppState
和 Editor
正确初始化我的 Session
,然后从我的 main
中初始化 运行?
how I can actually kick-start my transformer stack from my main function?
main =
flip evalStateT initialAppState $
flip evalStateT initialEditorState $
eventLoop
where
initialAppState =
error "Define me"
initialEditorState =
error "Define me"
Shouldn't Editor still be part of AppState because modifying it means modifying the overall state?
视情况而定。
还记得 Monad Transformer 的目的是以临时方式扩展功能吗?我的意思是临时的,不重写现有的代码库,而是通过添加到它。因此,如果您已经隔离了 API 的 Editor 和 AppState,则使用转换器堆栈将它们组合到另一个 "dome" 模块中会更容易。
OTOH,从初始架构的角度来看,AppState 是一个包含 Editor(我将其命名为 EditorState)等内容的数据结构是完全有道理的。在这种情况下,AppState 的API 应该封装Editor 的API。 "lens" 库将帮助您处理此类复合数据结构(尽管我必须提到它的学习曲线很陡)。