我试图弄清楚如何读取以下类类型定义:
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
。
答案 0 :(得分:5)
m -> r
是一个功能依赖项,它大致指出,当尝试选择要使用的MonadReader
实例时,知道m
就足以知道r
。换句话说,您无法使用相同的m
定义不同的r
来定义两个单独的实例。
现在,要确定要使用ask
的哪个定义,我们转向推论。根据其定义,我们知道ask
的类型为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
不一定是一个函数。它也可能是类型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"