StateT
monad 转换器的源代码
有两个函数
execStateT
和 evalStateT
在其定义中具有 Monad m
约束:
evalStateT :: Monad m => StateT s m a -> s -> m a
evalStateT m s = do
~(a, _) <- runStateT m s
return a
execStateT :: Monad m => StateT s m a -> s -> m s
execStateT m s = do
~(_, s') <- runStateT m s
return s'
使用
Functor
约束的实现不也可以工作吗?
evalStateT :: Functor m => StateT s m a -> s -> m a
evalStateT = (fmap fst .) . runStateT
execStateT :: Functor m => StateT s m a -> s -> m s
execStateT = (fmap snd .) . runStateT
施加更严格的约束是否有原因?
施加更严格的约束是否有原因?
很难说,但我想到两个原因:
将其用作
Functor
没有多大意义:单子转换器只有使用它来转换单子才有意义。因此,最终 evalStateT
将(几乎)始终与 m
的 Monad
实例一起工作,因为首先构造 StateT s m a
的事物需要 m
成为 Monad
;和
Monad
类型约束早在 2009 年 1 月就已在 transformers-0.0.0.0
中实现。当时 Functor-Applicative-Monad 提案尚未提出(那是在 2014 年)。所以这意味着到那时,Monad
不是Applicative
的子类,Applicative
也不是Functor
的子类。因此,类型 T 可以是 Monad
的实例,而不是 Functor
或 Applicative
的实例。
因此,通过添加
Functor
作为类型约束,实际上常常会让情况变得更糟:作为 Monad
实例的某些类型不是 Functor
s yet 的实例,因此您可以排除某些类型对于 StateT
仍然有用。事实上,Monad
类型不需要是Applicative
和Functor
的实例,这一事实总是有点错误,但需要一段时间才能消除损坏。