我还是Haskell的新手,并且无法为函数找到正确的类型签名。
我使用http-conduit
和authenticate-oauth
具有副作用的相当直接的功能,所以我不太关心返回值:
executeOAuthRequest oauth cred request =
withManager $ \manager -> do
signed <- signOAuth oauth cred request
http signed manager
我想指定正确的类型签名,但GHCi的输出对我来说非常可怕:
executeOAuthRequest
:: (monad-control-0.3.2.3:Control.Monad.Trans.Control.MonadBaseControl
IO m,
Control.Monad.Trans.Resource.Internal.MonadThrow m,
Control.Monad.Trans.Resource.Internal.MonadUnsafeIO m,
Control.Monad.IO.Class.MonadIO m) =>
OAuth
-> Credential
-> Request
-> m (Response (ResumableSource (ResourceT m) ByteString))
前三个论点(OAuth
,Credential
,Request
)对我有意义,但我不理解m
和奇迹的长期先决条件如果有必要指定GHCi建议的完整返回值。
我不想仅仅提供正确的签名,而是要了解查找和减少正确签名背后的过程。
答案 0 :(得分:8)
GHCi为您提供了最多态的签名,从m
模块,MonadThrow
等读取“任何类型Monad.Trans.Resource.Internal
,它是类MonadIO
的一个实例” 。类型检查器有点结合了您在executeOAuthRequest
中编写的那些多态函数类型引入的所有约束。
这是一个简单的例子:
Prelude> let f n = n + 1
Prelude> :t f -- GHC infers the polymorphic signature constrained to `Num`:
f :: Num a => a -> a
Prelude> let f :: Int -> Int ; f n = n + 1
Prelude> :t f
f :: Int -> Int
可能是满足函数中所有约束的唯一类型是IO
,或者可能有几个。通常的检查方法是阅读黑线鳕,或者做例如:
Prelude> :info IO
...
instance Monad IO -- Defined in ‘GHC.Base’
instance Functor IO -- Defined in ‘GHC.Base’
Prelude> :info Monad
...
instance Monad [] -- Defined in ‘GHC.Base’
instance Monad IO -- Defined in ‘GHC.Base’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
因此,如果你只在IO
中使用你的功能,你可以给它类型:
executeOAuthRequest
:: OAuth
-> Credential
-> Request
-> IO (Response (ResumableSource (ResourceT m) ByteString))
或者您可以保留多态签名,例如,如果您在库中导出此函数并认为您的用户可能希望在不同的monad中使用它(甚至可能通过定义自己的新类型并使其成为实例MonadIO
,MonadThrow
等)