为什么Haskell中不存在MonadMaybe类型类?
关于
MonadMaybe类型类的疑问与探索 我对MonadState的理解是:任何实现这个类型类的类型(或者类型组合,比如ReaderT r m a)都必须支持get+put(或者仅state)操作,才能表现得像State单子——它本质是个Monad,但又多了这些专属操作,get和put就是定义它特性的核心API。
那如果存在MonadMaybe类型类,它会是什么样?如果一个单子栈想表现得像Maybe单子,是不是就得实现这个类型类?这到底意味着什么?毕竟Maybe本身就是个Monad,但它好像没有能定义自身特性的专属API,不是吗?
我看过Reddit上Edward Kmett的回答,但没太搞懂,可能是当局者迷。
这个类型类的定义会是怎样的?
class Monad m => MonadMaybe m where ...???
具体代码示例分析
先看一段硬编码了单子栈顺序的代码:
foo :: Monad m => MaybeT (StateT Int (ReaderT Int m)) Int foo = do s <- get r <- ask if s + r == 0 then mzero -- 见底部注释 (¹) else return $ s + r
这个栈的顺序是MaybeT→StateT→ReaderT,所以只能按这个顺序剥离运行:
bar :: IO (Maybe Int) bar = runMaybeT foo `evalStateT` 3 `runReaderT` 3
而不能写成下面这样:
bar :: IO (Maybe Int) bar = runMaybeT (foo `evalStateT` 3 `runReaderT` 3)
因为单子层必须从最外层开始剥离。
要让bar摆脱这种顺序限制,我们可以让m实现对应的类型类,改写foo的签名:
foo :: (MonadState Int m, MonadReader Int m) => MaybeT m Int foo = do s <- get r <- ask if s + r == 0 then mzero else return $ s + r
现在两种bar的写法都能正常运行了。
这时候我就在想,如果有MonadMaybe类型类,我就能把foo的签名改成这样:
foo :: (MonadMaybe m, MonadState Int m, MonadReader Int m) => m Int
这样一来,bar就可以用任意顺序剥离单子层:
bar :: IO (Maybe Int) bar = (runMaybeT foo) `evalStateT` 3 `runReaderT` 3 -- MSR bar = (runMaybeT foo) `runReaderT` 3 `evalStateT` 3 -- MRS bar = runMaybeT (foo `runReaderT` 3) `evalStateT` 3 -- RMS bar = runMaybeT (foo `evalStateT` 3) `runReaderT` 3 -- SMR bar = runMaybeT (foo `runReaderT` 3 `evalStateT` 3) -- RSM bar = runMaybeT (foo `evalStateT` 3 `runReaderT` 3) -- SRM
上面的注释用MSR这类缩写表示三个单子层的处理顺序。
(¹) 如果把runMaybeT改成(runMaybeT . forever),就能简洁表示一个可以永久运行、也可以通过mzero提前退出的计算。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

