【发布时间】:2014-06-05 18:38:21
【问题描述】:
我还是 Haskell 的新手,很难为函数找到正确的类型签名。
我有这个使用 http-conduit 和 authenticate-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))
前三个参数(OAuth、Credential、Request)对我来说很有意义,但我不明白 m 的长前提条件,并且想知道是否有必要将完整的返回值指定为GHCi 建议。
不仅仅是提供正确的签名,我还想了解查找和减少正确签名的过程是什么样的。
【问题讨论】:
-
请注意
IO实现了所有这些约束,因此如果您只需要使用IO,您可以删除约束并将m专门化为IO,如下所示:OAuth -> Credential -> Request -> IO (Respond (ResumableSource (ResourceT IO) ByteString)) -
@GabrielGonzalez 谢谢!这是因为 IO 是
* -> *还是因为它满足所有约束的另一个属性? -
@passy 没有。
* -> *是一种。它只意味着IO是一个类型构造函数(而IO a是任何类型a 的类型)。IO统计所有约束,因为声明了类型类实例。例如,IO有一个MonadIO实例。更复杂的类型签名很有用,因为还有其他类似于IO的 monad,可以使用它们来代替。 -
@passy 这个想法是这些约束使类型更加灵活,以便您的函数可以与
IO以外的 monad 一起使用。但是,如果您不需要额外的灵活性,您可以通过选择实现这些约束的特定 monad 来简化类型。