[英]Why doesn't print force entire lazy IO value?
I'm using http-client tutorial to get response body using TLS connection. 我正在使用http-client教程来使用TLS连接获取响应正文。 Since I can observe that print
is called by withResponse
, why doesn't print
force entire response to the output in the following fragment? 因为我可以观察到, print
由被称为withResponse
,为什么不print
强制在下面的代码片段输出整个响应?
withResponse request manager $ \response -> do
putStrLn $ "The status code was: " ++
body <- (responseBody response)
print body
I need to write this instead: 我需要这样写:
response <- httpLbs request manager
putStrLn $ "The status code was: " ++
show (statusCode $ responseStatus response)
print $ responseBody response
Body I want to print is a lazy ByteString. 我要打印的主体是一个懒惰的ByteString。 I'm still not sure whether I should expect print
to print the entire value. 我仍然不确定我是否应该期望print
打印出整个值。
instance Show ByteString where
showsPrec p ps r = showsPrec p (unpackChars ps) r
This doesn't have to do with laziness, but with the difference between the Response L.ByteString
you get with the Simple module, and the Response BodyReader
you get with the TLS module. 这并不一定与懒惰做的,但与之间的差异Response L.ByteString
你与单模获得,以及Response BodyReader
您使用TLS模块获得。
You noticed that a BodyReader
is an IO ByteString
. 您注意到, BodyReader
是IO ByteString
。 But in particular it is an action that can be repeated, each time with the next chunk of bytes. 但特别是,此操作可以重复,每次下一个字节块都可以重复。 It follows the protocol that it never sends a null bytestring except when it's at the end of file. 它遵循的协议是,除非它位于文件末尾,否则从不发送空字节串。 ( BodyReader
might have been called ChunkGetter
). ( BodyReader
可能被称为ChunkGetter
)。 bip
below is like what you wrote: after extracting the BodyReader
/ IO ByteString
from the Response
, it performs it to get the first chunk, and prints it. 下面的bip
就像您写的一样:从Response
提取BodyReader
/ IO ByteString
,它执行该操作以获取第一个块并进行打印。 But doesn't repeat the action to get more - so in this case we just see the first couple chapters of Genesis. 但是不会重复此操作以获取更多收益-因此在这种情况下,我们只看到《创世纪》的前几章。 What you need is a loop to exhaust the chunks, as in bop
below, which causes the whole King James Bible to spill into the console. 您需要的是一个循环来耗尽这些块,如下面的bop
所示,这会导致整个《詹姆斯国王圣经》溢出到控制台中。
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Client
import Network.HTTP.Client.TLS
import qualified Data.ByteString.Char8 as B
main = bip
-- main = bop
bip = do
manager <- newManager tlsManagerSettings
request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt"
withResponse request manager $ \response -> do
putStrLn "The status code was: "
print (responseStatus response)
chunk <- responseBody response
B.putStrLn chunk
bop = do
manager <- newManager tlsManagerSettings
request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt"
withResponse request manager $ \response -> do
putStrLn "The status code was: "
print (responseStatus response)
let loop = do
chunk <- responseBody response
if B.null chunk
then return ()
else B.putStr chunk >> loop
loop
The loop keeps going back to get more chunks until it gets an empty string, which represents eof, so in the terminal it prints through to the end of the Apocalypse. 循环不断返回以获取更多的块,直到获得代表eof的空字符串为止,因此在终端中它将一直打印到末日末尾。
This is behavior is straightforward but slightly technical. 这是很简单的行为,但是有点技术性。 You can only work with a BodyReader
by hand-written recursion. 您只能通过手写递归使用BodyReader
。 But the purpose of the http-client
library is to make things like http-conduit
possible. 但是http-client
库的目的是使诸如http-conduit
类的事情成为可能。 There the result of withResponse
has the type Response (ConduitM i ByteString m ())
. 那里withResponse
的结果的类型为Response (ConduitM i ByteString m ())
。 ConduitM i ByteString m ()
is how conduit types of a byte stream; ConduitM i ByteString m ()
是字节流的管道类型如何; this byte stream would contain the whole file. 该字节流将包含整个文件。
In the original form of the http-client
/ http-conduit
material, the Response
contained a conduit like this; 在http-client
/ http-conduit
资料的原始形式中, Response
包含这样的管道; the BodyReader
part was later factored out into http-client
so it could be used by different streaming libraries like pipes
. BodyReader
部分后来被分解到http-client
因此它可以被pipes
等不同的流媒体库使用。
So to take a simple example, in the corresponding http material for the streaming
and streaming-bytestring
libraries, withHTTP
gives you a response of type Response (ByteString IO ())
. 因此,举一个简单的例子,在与streaming
和streaming-bytestring
库相对应的http资料中, withHTTP
为您提供了响应类型Response (ByteString IO ())
。 ByteString IO ()
is the type of a stream of bytes arising in IO, as its name suggests; 顾名思义, ByteString IO ()
是IO中产生的字节流的类型; ByteString Identity ()
would be the equivalent of a lazy bytestring (effectively a pure list of chunks.) The ByteString IO ()
will in this case represent the whole bytestream down to the Apocalypse. ByteString Identity ()
等效于惰性字节串(实际上是纯块列表)。在这种情况下, ByteString IO ()
将代表整个字节流,直到天启。 So with the imports 所以跟进口
import qualified Data.ByteString.Streaming.HTTP as Bytes -- streaming-utils
import qualified Data.ByteString.Streaming.Char8 as Bytes -- streaming-bytestring
the program is identical to a lazy bytestring program: 该程序与惰性字节串程序相同:
bap = do
manager <- newManager tlsManagerSettings
request <- parseRequest "https://raw.githubusercontent.com/michaelt/kjv/master/kjv.txt"
Bytes.withHTTP request manager $ \response -> do
putStrLn "The status code was: "
print (responseStatus response)
Bytes.putStrLn $ responseBody response
Indeed it is slightly simpler, since you don't have "extract the bytes from IO`: 实际上,它稍微简单一些,因为您没有“从IO中提取字节:
lazy_bytes <- responseStatus response
Lazy.putStrLn lazy_bytes
but just write 但只要写
Bytes.putStrLn $ responseBody response
you just "print" them directly. 您只需直接“打印”它们即可。 If you want to view just a bit from the middle of the KJV, you can instead do what you would with a lazy bytestring, and end with: 如果您只想从KJV的中间查看,则可以使用懒惰的字节串来做,然后以:
Bytes.putStrLn $ Bytes.take 1000 $ Bytes.drop 50000 $ responseBody response
Then you will see something about Abraham. 然后,您将看到有关亚伯拉罕的信息。
The withHTTP
for streaming-bytestring
just hides the recursive looping that we needed to use the BodyReader
material from http-client
directly. 用于streaming-bytestring
的withHTTP
只是隐藏了我们直接从http-client
使用BodyReader
素材所需的递归循环。 It's the same eg with the withHTTP
you find in pipes-http
, which represents a stream of bytestring chunks as Producer ByteString IO ()
, and the same with http-conduit
. 例如,它与在pipes-http
找到的withHTTP
相同,后者代表Producer ByteString IO ()
表示字节串块流,而与http-conduit
相同。 In all of these cases, once you have your hands on the byte stream you handle it in the ways typical of the streaming IO framework without handwritten recursion. 在所有这些情况下,一旦掌握了字节流,就可以采用流IO框架的典型方式来处理它,而无需手写递归。 All of them use the BodyReader
from http-client
to do this, and this was the main purpose of the library. 他们所有人都使用来自http-client
的BodyReader
进行此操作,这是该库的主要目的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.