首页 > 解决方案 > 如何阅读 MonadReader 并询问定义?

问题描述

我想弄清楚如何阅读以下类类型定义:

Prelude Data.Functor.Identity Control.Monad.Reader> :i ask
class Monad m => MonadReader r (m :: * -> *) | m -> r where
  ask :: m r
  ...

m是更高种类的类型,它必须是monad.

但 是什么m -> r意思?

尝试玩一下ask如下:

Prelude Data.Functor.Identity Control.Monad.Reader> ask "Hello"
"Hello"

为什么我可以将参数传递给ask?查看类型签名:

ask :: m r

我无法识别,我可以将参数传递给ask.

标签: haskell

解决方案


m -> r一个函数依赖,它粗略地指出,当尝试选择MonadReader要使用的实例时,知道m就足够了r。换句话说,您不能定义两个具有相同m但不同的单独实例r

现在,为了确定ask使用哪个定义,我们转向类型推断。根据它的定义,我们知道ask有 type MonadReader r m => m r。从它在 中的使用ask "Hello",我们知道它也必须有一个像a -> b; 更具体地说,我们知道 与a统一String,因为那是 的类型"Hello"MonadReader r m => m r所以我们的任务是与统一String -> b

这很简单。用前缀符号重写String -> b并使用显式括号,我们可以将它们排列在一起:

MonadReader r m => m             r
                   ((->) String) b

所以m ~ ((->) String)r ~ b(尽管我们仍然不知道r/b应该是什么)。查看 的可用实例MonadReader,我们找到m ~ (->) String(或更一般地说,(->) r)的(唯一)实例:

instance MonadReader r ((->) r) where
    ask       = id
    local f m = m . f

所以现在我们知道,对于我们的选择m, ask = id。(这也让我们看到了这r ~ b ~ String一点。)

所以,ask "Hello" == id "Hello" == "Hello"

请注意,ask不一定必须是函数。它也可能是 type 的值Reader r a,在这种情况下runReader必须用于提取函数。

> :t runReader ask
runReader ask :: a -> a
> runReader ask "Hello"
"Hello"

它也可能是一个更复杂的单子,涉及ReaderT

> :t runReaderT ask
runReaderT ask :: Monad m => a -> m a
> runReaderT ask "Hello" :: Maybe String
Just "Hello"
> runReaderT ask "Hello" :: Either String String
Right "Hello"

推荐阅读