Haskell 类型推断似乎是一种魔术
我有以下代码段,无法对其进行配置,它是如何工作的:Haskell 类型推断似乎是一种魔术,haskell,Haskell,我有以下代码段,无法对其进行配置,它是如何工作的: embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int embedded = return 1 怎么可能只给出一个数字,然后得到诸如类型签名之类的信息呢?编译器是如何做到这一点的 措辞的选择有点不幸。表达式return 1返回类型签名MaybeT(除了ptt字符串(ReaderT()IO))Int的情况并非如此 正如n.m.在注释中所写,如果您不提供类型,则表达式更一般: Prelude
embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded = return 1
怎么可能只给出一个数字,然后得到诸如类型签名之类的信息呢?编译器是如何做到这一点的 措辞的选择有点不幸。表达式
return 1
返回类型签名MaybeT(除了ptt字符串(ReaderT()IO))Int
的情况并非如此
正如n.m.在注释中所写,如果您不提供类型,则表达式更一般:
Prelude> embedded = return 1
Prelude> :type embedded
embedded :: (Num a, Monad m) => m a
通过使用类型进行注释,您可以明确地声明您想要的不是一般性的东西
具体地说,您需要类型MaybeT(除了ptt字符串(ReaderT()IO))Int
return
如何工作<当m
是Monad
时,code>MaybeT ma是Monad
,并且return
的定义如下:
return = lift . return
return a = ExceptT $ return (Right a)
return = lift . return
右侧的return
是属于“内部”单子Monad
的return
函数,而lift
由MonadTrans
定义,并将基础单子值提升到MaybeT
这解释了MaybeT
值是如何创建的,但不是全部
在这种情况下,“内部”单子是除了字符串(ReaderT()IO)
,它是另一个单子(实际上是另一个MonadTrans
)<代码>返回
的定义如下:
return = lift . return
return a = ExceptT $ return (Right a)
return = lift . return
请注意,这是另一个嵌套的return
,其中右侧的return
属于另一个嵌套的Monad
在这种情况下,嵌套的Monad
是ReaderT()IO
——另一个MonadTrans
。它定义return
如下:
return = lift . return
return a = ExceptT $ return (Right a)
return = lift . return
还有另一个嵌套的返回
,其中右侧的返回
是为IO
定义的返回
(在这种特殊情况下)
所有这些都用a
参数化,在本例中,您将其限制为Int
因此
return1
首先获取纯值1
并将其打包到IO Int
中。然后将其提升到ReaderT()IO Int
,它再次被打包成ExceptT字符串(ReaderT()IO)Int
。最后,这个值被提升到MaybeT
您忘记了返回值return
不是关键字:它是一个函数:return::Monad m=>a->ma
。你说得对。编译器不会推断此类型签名。它将推断出一个更为普遍的结论。您提供了一个不太通用的签名来告诉编译器“嘿,我知道我在做什么,我想要这个”。但是如何成像,它是如何工作的?没有多少有效的方法MaybeT(除了字符串(ReaderT()IO))
是单子。所以MaybeT(除了字符串(ReaderT()IO))Int
是一个Monad m=>m Int
。因此,由于函数有一个return 1
,因此它调用与MaybeT关联的return
(除了ptt字符串(ReaderT()IO))
。这里没有类型推断。您已经告诉编译器嵌入的类型是什么return
将根据该类型的return
定义,简单地生成该类型的值。