Reputation: 7211
I'm still new to Haskell and am having trouble to find the correct type signature for a function.
I have this working, fairly straightforward function using http-conduit
and authenticate-oauth
which is side-effecting, so I don't care too much about the return value:
executeOAuthRequest oauth cred request =
withManager $ \manager -> do
signed <- signOAuth oauth cred request
http signed manager
I would like to specify the correct type signature, but the output from GHCi looks rather terrifying to me:
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))
The first three arguments (OAuth
, Credential
, Request
) make sense to me, but I don't understand the long precondition for m
and wonder if it's necessary to specify the full return value as GHCi suggests.
Rather than only providing the correct signature, I'd like to understand what the process behind finding and reducing the correct one looks like.
Upvotes: 5
Views: 267
Reputation: 16645
GHCi is giving you the most polymorphic signature, reading "any type m
which is an instance of the classes MonadThrow
from the Monad.Trans.Resource.Internal
module, MonadIO
, etc". The type-checker is sort of taking the union of all the constraints introduced by the types of those polymorphic functions you're composing in executeOAuthRequest
.
Here's a simple example:
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
It might be that the only type which satisfies all those constraints in your function is IO
, or there might be several. The usual way to check is by reading the haddocks, or doing e.g.
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’
So if you only use your function in IO
you can give it the type:
executeOAuthRequest
:: OAuth
-> Credential
-> Request
-> IO (Response (ResumableSource (ResourceT m) ByteString))
or you could keep the polymorphic signature, if for instance you're exporting this function in a library and think your users might want to use it in a different monad (maybe even by defining their own new type and making it an instance of MonadIO
, MonadThrow
, etc)
Upvotes: 8