CR *_*ost 8 io haskell types monad-transformers
所以在transformers我看来,
class (Monad m) => MonadIO m where
    -- | Lift a computation from the 'IO' monad.
    liftIO :: IO a -> m a
instance MonadIO IO where
    liftIO = id
我明白,这与MonadTrans不同的原因是,如果你有一些M1T (M2T (M3T (M4T IO))) x由4个组成的monad变换器组成,那么你不想,lift . lift . lift . lift $ putStrLn "abc"但你宁愿只是liftIO $ putStrLn "abc".
但是,IO当上面的基本定义似乎是这种奇怪的递归时,这种特殊性似乎非常奇怪liftIO.似乎应该为某些组合器设置一个newtype声明,(ExceptT :~: MaybeT) IO x这样lift你就可以得到一个单独的(我想这是一个monad变换器变换器吗?),或者是一些多参数类型,
class (Monad m) => MonadEmbed e m
    -- | Lift a computation from the `e` monad.
    embed :: e a -> m a
instance (Monad m) => MonadEmbed m m where
     embed = id
为什么不transformers使用这些方法之一,以便MonadTrans序列不必根植IO?只是事实上变形金刚处理所有"其他"效果,以便最底层的唯一东西要么Identity(已经处理过return :: a -> m a)还是IO?或者上面是否需要像transformers图书馆不愿意包含的UndecidableInstances ?或者是什么?
但是,这种特殊性
IO似乎非常奇怪
我质疑这是特定的假设IO.我还看到很多其他课程mtl.例如:
class Monad m => MonadError e m | m -> e where
    throwError :: e -> m a
    catchError :: m a -> (e -> m a) -> m a
class Monad m => MonadState s m | m -> s where
    get :: m s
    put :: s -> m ()
    state :: (s -> (a, s)) -> m a
......还有很多其他人.通常,mtl构建monadic动作的" 方法"是使用这些类型类多态操作,这样就不需要lift- 而是只需将操作单态化为适当的提升类型.例如,MonadError完全取代假设liftMaybe :: MonadMaybe m => Maybe a -> m a:而不是提升Maybe a值,人们将拥有Maybe a值调用的生成者throwError而return不是Nothing和Just.
对于某些组合器来说似乎应该有一个newtype声明,这样你
(ExceptT :~: MaybeT) IO x就可以得到一个单一的升力
有了这个提议,你需要(至少)两种不同类型的升降机:一部电梯从去m a到trans m a,和一部电梯从去trans m a到(trans' :~: trans) m a.具有处理两种提升的单个操作更均匀.
好像应该有一些多参数类型,
Run Code Online (Sandbox Code Playgroud)class Monad m => MonadEmbed e m -- | Lift a computation from the `e` monad. embed :: e a -> m a instance Monad m => MonadEmbed m m where embed = id
这种方法起初看起来很不错.但是,如果您尝试编写并使用此类,您将很快发现为什么所有mtl类都包含函数依赖项:实例MonadEmbed m m难以选择!即便是一个非常简单的例子
embed (Right ()) :: Either String ()
是一个含糊不清的错误.(毕竟,我们只知道Right 3 :: Either a ()对于某些人a- 我们还不知道,a ~ String所以我们不能选择MonadEmbed m m实例!)我怀疑你的大多数其他实例都会遇到类似的问题.如果你添加明显的函数依赖关系,你的类型推理问题就会消失,但是fundep检查会对你产生很大的限制:你可能只会从基础monad中提升,而不是像你希望的那样从任意中间monad中解除.这在实践中是一个非常痛苦的问题(并且" mtl方式"疼痛是如此之小),以至于没有完成mtl.
也就是说,您可能喜欢使用该transformers-base包装.
只是事实上变形金刚处理所有"其他"效果,以便最底层的唯一东西要么
Identity(已经处理过return :: a -> m a)还是IO?
正如你所说,最常见的基础是IO(我们已经拥有MonadIO)或Identity(通常只使用return一个纯粹的计算而不是一个提升的monadic计算).有时ST是一个方便的基础monad,但使用变换器ST比使用它们更为罕见IO.
这些Monad...类似乎主要是为了直接推广 monad的特征操作,如果monad被埋在一堆变换器下也能工作.这些操作通常是没有这么大集,例如State只需要get,put,state而且   modify如果你想要的,但仅此而已.
不是这样IO; 制作类中过多的基本IO操作方法是相当不切实际的MonadIO.你当然可以获得所有这些,如果你只是liftIO作为一个"转换函数"介绍,但我打赌这总是被认为是一个黑客.
此外:IO是最重要的非平凡基础单子; 仅仅因为这个原因,我不认为给它一个专用的升力功能是不合适的.
关于你的"单一升力是你所需要的"想法:问题:~:在于变换器现在形成二叉树而不是具有清晰层次结构的简单堆栈.这使得mtl类的整个想法更加成问题.