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.
IO
implements all those constraints, so if you only need to useIO
, you can just drop the constraint and specializem
toIO
like this:OAuth -> Credential -> Request -> IO (Respond (ResumableSource (ResourceT IO) ByteString))
– Gabriella Gonzalez* -> *
or is there another property because of which it satisfies all constraints? – passy* -> *
is a kind. It only means thatIO
is a type constructor (andIO a
is a type for any type a).IO
statisfies all constraints because the typeclasses instances are declared. as an example,IO
has aMonadIO
instance. The more complex type signature is useful because there are other monads which acts likeIO
, and which can be used instead. – Simon BergotIO
. However, if you don't need that extra flexibility you can simplify the type by choosing a specific monad that implements those constraints. – Gabriella Gonzalez