首页 文章

简化Haskell中的Monadic Type签名

提问于
浏览
5

我还是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 回答

  • 8

    GHCi为您提供了最多态的签名,读取“任何类型 m ,它是 Monad.Trans.Resource.Internal 模块中 MonadThrow 类的实例, 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 等)

相关问题