为什么选择 WrappedMonad 和 WrappedArrow?

Why WrappedMonad and WrappedArrow?

为什么存在 WrappedMonadWrappedArrow 类型?是因为 Monad 不是 Applicative 吗?鉴于 WrappedArrow 存在,实例

是否应该
Arrow a => Applicative (Arrow a b) 

只需内置到 Haskell 本身,就像 Applicative 现在是 Monad?

的超类一样

WrappedMonad 差不多。我猜它正在变得(也许已经)基本上过时了。但是WrappedArrow比较难,因为Arrow类型和Applicative类型有不同的种类,* -> * -> ** -> *。由于 GHC 实例解析的工作方式,添加实例(我假设额外的 Arrow 是一个错字)

instance Arrow a => Applicative (a b)

意味着 no 具有两个或更多参数的类型构造函数然后可以给出 Applicative 而不会给出 Arrow - 这看起来相当激烈。

将超类 Applicative (a b) => 添加到 Arrow a 的反向选项似乎更可口 - 除了您不能拥有像 b 这样的 forall'ed 类型的超类。这样的超类对其他事情也很有用,并且已经被多次建议,所以我认为很难实现。

我觉得 the DerivingVia extension 为这种新型包装器赋予了新的生命力。让我们假设,无论出于何种原因,我们想为一个类型编写 MonadMonadPlus 实例,然后为 ApplicativeAlternative:

搭载它们
newtype StT s m a = StT { runStT :: s -> m (a, s) }
    deriving Functor

instance Monad m => Monad (StT s m) where
    return a = StT $ \s -> return (a, s)
    m >>= f = StT $ \s -> m `runStT` s >>= \(a, t) -> f a `runStT` t

instance MonadPlus m => MonadPlus (StT s m) where
    mzero = StT $ \_ -> mzero
    m `mplus` n = StT $ \s -> (m `runStT` s) `mplus` (n `runStT` s)

通常,我们必须编写样板实例:

instance Monad m => Applicative (StT s m) where
    pure = return
    (<*>) = ap

instance MonadPlus m => Alternative (StT s m) where
    empty = mzero
    (<|>) = mplus

对于 DerivingViaWrappedMonad 可以用一种在我看来更好的方式拼写出来。

newtype StT s m a = StT { runStT :: s -> m (a, s) }
    deriving Functor
    deriving (Applicative, Alternative) via WrappedMonad (StT s m)

请注意,先前存在的派生子句不受影响。另一个不错的地方是推断出必要的超类约束。