如何阅读MonadReader并询问定义?

时间:2019-03-17 13:39:20

标签: haskell

我试图弄清楚如何读取以下类类型定义:

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

1 个答案:

答案 0 :(得分:5)

m -> r是一个功能依赖项,它大致指出,当尝试选择要使用的MonadReader实例时,知道m就足以知道r。换句话说,您无法使用相同的m定义不同的r来定义两个单独的实例。

现在,要确定要使用ask的哪个定义,我们转向推论。根据其定义,我们知道ask的类型为MonadReader r m => m r。通过在ask "Hello"中使用它,我们知道它还必须具有类似a -> b的类型;更具体地说,我们知道aString统一,因为这是"Hello"的类型。因此,我们的任务是将MonadReader r m => m rString -> 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

因此,现在我们知道,对于我们选择的mask = id。 (这也让我们看到了r ~ b ~ String。)

因此,ask "Hello" == id "Hello" == "Hello"

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

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

也可能是涉及ReaderT的更复杂的monad:

> :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"