简化Haskell中的Monadic Type签名

时间:2014-04-21 16:51:14

标签: haskell types

我还是Haskell的新手,并且无法为函数找到正确的类型签名。

我使用http-conduitauthenticate-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))

前三个论点(OAuthCredentialRequest)对我有意义,但我不理解m和奇迹的长期先决条件如果有必要指定GHCi建议的完整返回值。

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

1 个答案:

答案 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中使用它(甚至可能通过定义自己的新类型并使其成为实例MonadIOMonadThrow等)