简化Haskell中的Monadic Type签名

pas*_*ssy 5 haskell types

我还是Haskell的新手,我很难找到函数的正确类型签名.

我有这个工作,使用相当简单的功能http-conduit,authenticate-oauth这是副作用,所以我不太关心返回值:

executeOAuthRequest oauth cred request =
    withManager $ \manager -> do
        signed <- signOAuth oauth cred request
        http signed manager
Run Code Online (Sandbox Code Playgroud)

我想指定正确的类型签名,但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))
Run Code Online (Sandbox Code Playgroud)

前三个参数(OAuth,Credential,Request)道理给我,但我不明白的长期前提m,不知是否有必要为GHCI建议指定完整的返回值.

我不想仅仅提供正确的签名,而是想了解查找和减少正确签名背后的过程.

jbe*_*man 8

GHCI是给你的最具多态性的签名,阅读"任何类型m这是类的一个实例,MonadThrowMonad.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
Run Code Online (Sandbox Code Playgroud)

可能是满足函数中所有这些约束的唯一类型是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’
Run Code Online (Sandbox Code Playgroud)

因此,如果你只使用你的函数,IO你可以给它类型:

executeOAuthRequest
  :: OAuth
     -> Credential
     -> Request
     -> IO (Response (ResumableSource (ResourceT m) ByteString))
Run Code Online (Sandbox Code Playgroud)

或者你可以保持多态签名,举例来说如果你在一个库中导出此功能,并认为你的用户可能希望在不同的单子使用它(甚至通过自定义新型并使它的一个实例MonadIO,MonadThrow,等等)