我正在尝试构建一个简单的网络抓取器,以便从维基百科获取一些文本语料库。我想使用他们的REST API在Haskell中构建一个简单的HTTP客户端。
为此,我转向了Network.HTTP.Simple包。 在他们的教程中,他们提供了以下代码片段,我可以很好地运行。
#!/usr/bin/env stack
{- stack --install-ghc --resolver lts-5.13 runghc
--package http-conduit
--package yaml
-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson (Value)
import qualified Data.ByteString.Char8 as S8
import qualified Data.Yaml as Yaml
import Network.HTTP.Simple
main :: IO ()
main = do
response <- httpJSON "http://httpbin.org/get"
putStrLn $ "The status code was: " ++
show (getResponseStatusCode response)
print $ getResponseHeader "Content-Type" response
S8.putStrLn $ Yaml.encode (getResponseBody response :: Value)
为了理解代码,我注释掉了最后一行(以S8.putStrLn
开头的那行...,现在代码中断了。错误是
No instance for (Yaml.FromJSON a0) arising from a use of ‘httpJSON’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Yaml.FromJSON
aeson-1.2.1.0:Data.Aeson.Types.Internal.DotNetTime
-- Defined in ‘aeson-1.2.1.0:Data.Aeson.Types.FromJSON’
instance Yaml.FromJSON Value
-- Defined in ‘aeson-1.2.1.0:Data.Aeson.Types.FromJSON’
instance Yaml.FromJSON
attoparsec-0.13.1.0:Data.Attoparsec.Number.Number
-- Defined in ‘aeson-1.2.1.0:Data.Aeson.Types.FromJSON’
...plus 78 others
所以我的问题是:(1(所以我的猜测是,getResponseBody
强制httpJSON
的类型签名,所以歧义被解除了。但是怎么做呢?(2(我可以在不调用getResponseBody
的情况下消除表达式的歧义吗?我有哪些选项可以修复多态函数的返回类型?
编辑:我正在用cabal run
运行它,因为我还没有安装堆栈。我没想到这会改变事情,但谁知道呢......可能会提供线索。
类型检查
我们有这个签名:getResponseBody :: Response a -> a
.
起初,就在httpJSON
之后,我们已经response :: Response a0
了一些未知a0
。
然后我们写getResponseBody response
,它的类型a0
,仍然未知。
然后我们注释getResponseBody response :: Value
,所以a0 ~ Value
,现在实例解析有一个具体的类型可以使用。
限制response
类型的替代方法
您可以在使用response
值的任何位置直接对其进行注释,例如,您可以在代码段中间编写getResponseStatusCode (response :: Response Value)
。
使用ScopedTypeVariables
扩展名,您还可以注释绑定它的模式:(response :: Response Value) <- httpJSON "..."
。
a0
类型变量也出现在httpJSON
的结果类型中,因此您也可以对其进行注释。
response <- httpJSON "..." :: IO (Response Value)
对于TypeApplications
,这里有更多的选择,任何一个都应该足以让类型检查器推断出a0 ~ Value
:
response <- httpJSON @_ @Value "..."
getResponseStatusCode @Value response
getResponseHeader @Value "..." response
getResponseBody @Value response