在MonadTrans课程中:
class MonadTrans t where
-- | Lift a computation from the argument monad to the constructed monad.
lift :: Monad m => m a -> t m a
为什么t m
不被限制为Monad?即,为什么不:
{-# LANGUAGE MultiParamTypeClasses #-}
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
如果答案是“因为那就是它的方式”,那很好 - 这只会让n008感到困惑。
答案 0 :(得分:14)
您建议如下:
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
...但这真的意味着你想要的吗?对于所有t
MonadTrans
m :: * -> *
是m
的实例,您似乎想要表达“类型Monad
可能是t m
的实例” ,Monad
也是t
“的实例。
上面实际上面的类定义更像是“m
类型MonadTrans
可能构成t m
的实例,如果对于这些特定类型, Monad
是Data.Set
“的一个实例。仔细考虑差异,以及可能不是您想要的实例的隐含潜力。
在一般情况下,类型类的每个参数都是一个独立的“参数”,这个事实一直是人们试图使用MPTC时头痛和GHC扩展的丰富来源。
这并不是说无论如何都不能使用这样的定义 - 正如你所指出的那样,目前的定义也不理想。古老的问题“为什么Functor
不是ConstraintKinds
”是相关的,而这些问题有助于推动最近的MonadTrans
愚蠢行为。
这里的“为什么不”的最终答案几乎可以肯定是Daniel Fischer在评论中给出的答案 - 因为{{1}}是非常核心的功能,所以要让它依赖于一些可怕的级联越来越神秘的GHC扩展。