Hackage有几个monad变换器包:
(也许我错过了一些)
我们应该使用哪一个?
mtl是Haskell平台中的一个,但我一直听说reddit它是不酷的.
但无论如何,选择有什么不好,这不是一件好事吗?
好吧,我看到数据访问器的作者如何必须使所有这些满足流行的选择:
我想如果这种情况继续下去,例如几个竞争的箭头包演变,我们可能会看到类似:spoonklink-arrows-transformers,spoonklink-arrows-monadLib,spoonklink-tfArrows-transformers,spoonklink-tfArrows-monadLib,...
然后我担心如果spoonklink被分叉,Hackage将耗尽磁盘空间.:)
问题:
我试图采取例如ExceptT a (StateT A M),对于一些具体类型A和monad M,并将它们包装到我的新自定义monad中.
首先,我确定了StateT A M在其他环境中经常出现,因此我决定这将是最好的单独包装在一个单子M1,然后包装ExceptT a M1成M2.
所需的属性是make M1和的M2实例MonadState和类M(假设它被调用MyMonadClass).也M2应该是一个实例MonadError.
首先我从简单类型的同义词开始:
type MyState = StateT A M
type MyBranch a = ExceptT a MyState
Run Code Online (Sandbox Code Playgroud)
然后我想我会首先勾画实例声明(没有实现实例),这就是我第一次被卡住的地方.instance MonadState A (MyState)似乎不是正确的语法.我以为我必须创建newtype MyState' a = StateT a M然后type MyState = MyState A(不要在没有必要的地方使用语言扩展).
然而,一旦我开始将同义词转换为newtype声明,我开始失去与StateT A M和 …
有时我需要使用几个嵌套MonadTrans.例如,我会在一个MaybeT内部ExceptT,模仿continue和break命令式编程:
runExceptT . forM [1..] $ \ _ -> runMaybeT $ do
...
mzero -- this mimics continue
lift $ throwE "..." -- this mimics break
lift . lift $ putStrLn "Hello!"
...
Run Code Online (Sandbox Code Playgroud)
但是,正如上面的代码所示,每次我需要IO在这个"人工循环"中进行任何操作时,我需要lift . lift在它之前放一个丑陋的东西.想象一下,如果我有更复杂的嵌套和大量IO操作,这很快就会成为一种厌恶.我如何使代码更清晰,更简洁?