Haskell HTTP 响应中 ByteString 的笨拙类型签名
Clumsy Looking Type Signature for ByteStrings in Haskell HTTP Response
我正在试验 http-conduit 库并有这个简单的例子:
#!/usr/bin/env stack
{- stack
--resolver lts-7.12
--install-ghc
runghc
--package http-conduit
-}
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Conduit
import Data.ByteString.Lazy.Internal
getUrl :: IO (Data.ByteString.Lazy.Internal.ByteString) ---eeew!
getUrl = do
resp <- simpleHttp "http://www.whosebug.com"
return resp
我从 了解到,我应该更喜欢将响应作为 ByteString 而不是 [Char] 或 String。我假设 OverloadedStrings pragma 可能会减少这个问题,但对于我的输出类型似乎没有改变。
该函数工作正常,尽职尽责地为 SO 的主页打印出一个简单的 http 响应,但该类型签名看起来真的很难看:
getUrl :: IO (Data.ByteString.Lazy.Internal.ByteString)
而且我不得不说我从 Internet 示例中很少看到类似的东西(我们有比椭圆形 Java 导入更多的点,伙计)。那正确吗?如果我想 return 一个响应然后开始解析它,比如使用 HXT 或 tagsoup 或 attoparsec,这是正确的方法还是类型签名?
我注意到,例如,当我开始添加接受参数的能力时,这变得更加丑陋,例如提供不同的 URL:
import Network.HTTP.Conduit
import Data.ByteString.Lazy.Internal
-- alright, first arg is now string for my url...
getUrl :: String -> IO (Data.ByteString.Lazy.Internal.ByteString)
getUrl url = do
resp <- simpleHttp url
return resp
main :: IO (ByteString) -- what?! inside the () ?
main = do
getUrl "https://www.whosebug.com"
这似乎不健康。我应该如何理解如何正确构建它?
您始终可以使用限定路径编写类型。但是,由于您已经导入 Data.ByteString.Lazy.Internal
并且除非您在范围内有其他 ByteString
类型(如严格类型),您可以简单地省略 Data.ByteString.Lazy.Internal
:
getUrl :: IO ByteString
此外,除非您有特殊需要导入 Internal
,否则我建议您只导入 Data.ByteString.Lazy
(它还会导出您正在使用的惰性 ByteString
类型)。如果范围内同时有严格和惰性 ByteString
,我会导入它们:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
那么 BS.ByteString
是严格类型,BL.ByteString
是惰性类型 - 不需要写出完整的 Data.ByteString.ByteString
或 Data.ByteString.Lazy.ByteString
.
还值得一提(感谢@duplode),通常最好导入任何一个 bytestring 模块,因为它们定义了一大堆与 Prelude(以及彼此)冲突的函数。
最后,请注意类型周围的括号本身没有任何作用。 (ByteString)
和 ByteString
是相同的。因此,我不会包括它们。
与你的问题无关,但对你的单子代码有一些评论:
每次你写这样的东西
do x <- e
return x
可以直接替换为e
.
每次你写这样的东西
do e
可以换成e
.
我正在试验 http-conduit 库并有这个简单的例子:
#!/usr/bin/env stack
{- stack
--resolver lts-7.12
--install-ghc
runghc
--package http-conduit
-}
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Conduit
import Data.ByteString.Lazy.Internal
getUrl :: IO (Data.ByteString.Lazy.Internal.ByteString) ---eeew!
getUrl = do
resp <- simpleHttp "http://www.whosebug.com"
return resp
我从
该函数工作正常,尽职尽责地为 SO 的主页打印出一个简单的 http 响应,但该类型签名看起来真的很难看:
getUrl :: IO (Data.ByteString.Lazy.Internal.ByteString)
而且我不得不说我从 Internet 示例中很少看到类似的东西(我们有比椭圆形 Java 导入更多的点,伙计)。那正确吗?如果我想 return 一个响应然后开始解析它,比如使用 HXT 或 tagsoup 或 attoparsec,这是正确的方法还是类型签名?
我注意到,例如,当我开始添加接受参数的能力时,这变得更加丑陋,例如提供不同的 URL:
import Network.HTTP.Conduit
import Data.ByteString.Lazy.Internal
-- alright, first arg is now string for my url...
getUrl :: String -> IO (Data.ByteString.Lazy.Internal.ByteString)
getUrl url = do
resp <- simpleHttp url
return resp
main :: IO (ByteString) -- what?! inside the () ?
main = do
getUrl "https://www.whosebug.com"
这似乎不健康。我应该如何理解如何正确构建它?
您始终可以使用限定路径编写类型。但是,由于您已经导入 Data.ByteString.Lazy.Internal
并且除非您在范围内有其他 ByteString
类型(如严格类型),您可以简单地省略 Data.ByteString.Lazy.Internal
:
getUrl :: IO ByteString
此外,除非您有特殊需要导入 Internal
,否则我建议您只导入 Data.ByteString.Lazy
(它还会导出您正在使用的惰性 ByteString
类型)。如果范围内同时有严格和惰性 ByteString
,我会导入它们:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
那么 BS.ByteString
是严格类型,BL.ByteString
是惰性类型 - 不需要写出完整的 Data.ByteString.ByteString
或 Data.ByteString.Lazy.ByteString
.
还值得一提(感谢@duplode),通常最好导入任何一个 bytestring 模块,因为它们定义了一大堆与 Prelude(以及彼此)冲突的函数。
最后,请注意类型周围的括号本身没有任何作用。 (ByteString)
和 ByteString
是相同的。因此,我不会包括它们。
与你的问题无关,但对你的单子代码有一些评论:
每次你写这样的东西
do x <- e return x
可以直接替换为
e
.每次你写这样的东西
do e
可以换成
e
.