Haskell 如何阅读蒙纳恐惧症并询问其定义?
我试图弄明白,如何阅读下面的类类型定义:Haskell 如何阅读蒙纳恐惧症并询问其定义?,haskell,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
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
m->r
是一个函数依赖项,它粗略地说明,当试图选择要使用的monawarder
实例时,知道m
就足以知道r
。换句话说,不能用相同的m
定义两个不同的r
实例
现在,为了确定使用ask
的哪个定义,我们转向类型推断。从它的定义中,我们知道ask
的类型是monaderrm=>mr
。从它在ask“Hello”
中的使用,我们知道它还必须有一个类似a->b
的类型;更具体地说,我们知道a
与String
相统一,因为这是的类型“Hello”
。因此,我们的任务是将monaderrm=>mr
与String->b
统一起来
这很简单。在前缀符号中重写String->b
,并使用显式括号,我们可以将它们排列在一起:
MonadReader r m => m r
((->) String) b
所以m~(-)字符串)
和r~b
(尽管我们仍然不知道r/b
应该是什么)。查看可用的monawarder
,我们发现m-String
(或者更一般地说,(>)r
)的(唯一)实例:
现在我们知道,对于选择m
,ask=id
。(这让我们也可以看到r~b~字符串
)
因此,询问“Hello”==id“Hello”==“Hello”
请注意,ask
不一定是一个函数。它也可能是Reader ra
类型的值,在这种情况下,必须使用runReader
来提取函数
> :t runReader ask
runReader ask :: a -> a
> runReader ask "Hello"
"Hello"
它也可能是一个更复杂的monad,涉及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"
我认为这个想法是,当你试图调用
字符串上的ask
时,类型推断允许m
与函数monad统一,因此你最终得到ask::String->String
m->r
是一个函数依赖项;知道m
就足以推断出r
是什么。本质上,它说,你不能为同一个monad定义多个monader
实例,但是使用不同的r
s。我不知道如何给出详细的答案,但简而言之:m->r
是一个问题。函数本身就是一个Monad实例,所以当你问“Hello”
时,Haskell会选择这个Monad。(事实上,这只是阅读器Monad本身。)我也不理解ask::monaderrm=>mr
类型签名。为什么类型签名包含=>
?这意味着什么?它意味着ask
是任何monadm
和类型r
的类型m
的值,其中有一个monawarder
实例。这是否意味着类型r
的monad实例?不,r
是monadm
所“包装”的类型。大多数情况下,monawarder
的实例(粗略地说)是函数、Reader
(本身只是函数的包装器),或者是使用ReaderT
构建的monad。这意味着ask
几乎总是一个值,或者可以从中提取函数。
> :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"