我对简单(单焦点)Haskell 程序有一些经验,但现在我正在尝试用 Haskell 编写更大的应用程序。我在构建应用程序时遇到问题。
比方说,我们有三个模块(概念)的应用程序- Main,Logic和AppIO。Main在启动程序和使用功能Logic和AppIO做的工作。Logic抽象应用程序逻辑,我们需要它的多个实现。使用哪种Logic实现Main由用户配置决定。AppIO用于与外界对话的函数。
我的Main模块有一个newtype App = App { unapp :: ReaderT r (ExceptT e m) a }monad 转换器。同样,Logic并AppIO拥有自己的 monad 变压器堆栈。我正在考虑在基础上创建一个App带有Logic和AppIO转换器的monad 转换器。
在这一点上,我有一些问题。
Logic并且AppIO拥有自己的 monad 变压器堆栈还是应该App在他们的类型签名中拥有?我不喜欢App使用模块类型,因为我认为模块应该相互不可知。Logic如果我不让它本身成为变压器,我将如何给出自己的状态?Logic并且在他们的转换器堆栈中AppIO有他们自己的ExceptTmonad 来处理他们自己的错误类型,即MonadError LogicError和MonadError IOError,他们将如何与Applevel一起工作ExceptT?我需要编写lift函数吗?如果我编写lift函数,那么如何在函数调用时更新内部状态(例如RandomGen)Logic?据我了解lift将运行 monad,因此它的状态丢失了?Logic以便它具有多个可以相互交换的实现而无需更改任何其他内容?我应该定义一个class Logic吗?或者它应该是一个data Logic以它的接口函数为成员的?