因此,我有一个项目,我认为它足够简单,可以学习,但又足够复杂,所以我想使用Happstack库编写。在最基本的层面上,这个项目只是一个花哨的文件服务器,带有一些特定于域的REST方法(或者其他什么,我并不真正关心它是否是真正的RESTful )来搜索和获取所说的文件和元数据。因为我现在也在尝试学习monad transformers,所以我决定这将是一个学习的完美项目。然而,我在启动它时遇到了一些困难,特别是在如何构造我的转换器堆栈方面。
现在,我只关心几件事:配置、错误报告、状态和日志记录,所以我从
newtype MyApp a = MyApp {
runMyApp :: ReaderT Config (ErrorT String (StateT AppState IO)) a
} deriving (...)因为我总是在IO中,所以我可以很容易地使用hslogger来处理我的日志。但我也知道我需要使用ServerPartT来与Happstack交互,因此
runMyApp :: ReaderT Config (ErrorT String (StateT AppState (ServerPartT IO))) a我可以让它运行,查看请求等,但我遇到的问题是,为了使用dir、path和ok等方法,我需要为它实现FilterMonad,但我不知道如何为这种类型实现它。我只需要它将过滤器向下传递到底层的monad。有人能给我一些关于如何实现这个显然至关重要的类型类的建议吗?或者,如果我只是在做一些非常错误的事情,那就引导我朝着正确的方向前进。我只关注了Happstack几天,而转换器对我来说仍然很新。我认为我对它们的理解已经足够危险,但我对它们的了解还不够多,以至于我不能自己实现一个。我们非常感谢您能提供的任何帮助!
(X-从/r/haskell发布)
发布于 2013-07-02 08:54:42
对你来说最简单的事情就是从你的堆栈中去掉ErrorT。如果查看here,您可以看到Happstack为StateT和ReaderT定义了FilterMonad的内置直通实例,但没有为ErrorT定义任何实例。如果您确实希望将ErrorT保留在堆栈中,那么您需要为它编写一个直通实例。它可能看起来很像ReaderT的版本。
instance (FilterMonad res m) => FilterMonad res (ReaderT r m) where
setFilter f = lift $ setFilter f
composeFilter = lift . composeFilter
getFilter = mapReaderT getFilter我倾向于认为你不应该将ErrorT嵌入到你的应用程序monad中,因为你不会总是处理可能失败的计算。如果确实需要处理代码的某一部分中的故障,只需在该部分中包装runErrorT,然后根据需要使用ErrorT、lift和return,就可以轻松地处理失败。此外,transformer堆栈中的额外层会在每次绑定时增加性能负担。因此,虽然monad转换器的可组合性真的很好,但当性能是一个重要的考虑因素时,您通常希望谨慎地使用它们。
另外,我建议使用EitherT而不是ErrorT。这样你就可以使用神奇的errors package了。它有很多非常常见的方便函数,比如hush、just等。
此外,如果你想看到你正在尝试做的事情的真实例子,请查看Snap的Handler monad。您的MyApp monad正是snaplets设计要解决的问题。Handler有一些额外的复杂性,因为它被设计成以通用的方式解决问题,这样Snap用户就不需要自己构建这个通用的转换器堆栈。但是,如果你看一下underlying implementation,你会发现它的核心实际上只是Reader和State monad被压缩成一个。
https://stackoverflow.com/questions/17334877
复制相似问题