为什么选择 WrappedMonad 和 WrappedArrow?
Why WrappedMonad and WrappedArrow?
为什么存在 WrappedMonad
和 WrappedArrow
类型?是因为 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 为这种新型包装器赋予了新的生命力。让我们假设,无论出于何种原因,我们想为一个类型编写 Monad
和 MonadPlus
实例,然后为 Applicative
和 Alternative
:
搭载它们
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
对于 DerivingVia
,WrappedMonad
可以用一种在我看来更好的方式拼写出来。
newtype StT s m a = StT { runStT :: s -> m (a, s) }
deriving Functor
deriving (Applicative, Alternative) via WrappedMonad (StT s m)
请注意,先前存在的派生子句不受影响。另一个不错的地方是推断出必要的超类约束。
为什么存在 WrappedMonad
和 WrappedArrow
类型?是因为 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 为这种新型包装器赋予了新的生命力。让我们假设,无论出于何种原因,我们想为一个类型编写 Monad
和 MonadPlus
实例,然后为 Applicative
和 Alternative
:
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
对于 DerivingVia
,WrappedMonad
可以用一种在我看来更好的方式拼写出来。
newtype StT s m a = StT { runStT :: s -> m (a, s) }
deriving Functor
deriving (Applicative, Alternative) via WrappedMonad (StT s m)
请注意,先前存在的派生子句不受影响。另一个不错的地方是推断出必要的超类约束。