gpt4 book ai didi

haskell - 为什么打印不强制整个惰性 IO 值?

转载 作者:行者123 更新时间:2023-12-02 20:53:08 25 4
gpt4 key购买 nike

我正在使用 http-client使用 TLS 连接获取响应主体的教程。因为我可以观察到 print 是由 withResponse 调用的,为什么 print 不强制对以下片段中的输出做出完整响应?

withResponse request manager $ \response -> do
putStrLn $ "The status code was: " ++
body <- (responseBody response)
print body

我需要这样写:

response <- httpLbs request manager

putStrLn $ "The status code was: " ++
show (statusCode $ responseStatus response)
print $ responseBody response

我要打印的正文是一个惰性 ByteString。我仍然不确定我是否应该期望 print 打印整个值。

instance Show ByteString where
showsPrec p ps r = showsPrec p (unpackChars ps) r

最佳答案

这与懒惰无关,但与您使用 Simple 模块获得的 Response L.ByteString 和您获得的 Response BodyReader 之间的区别有关使用 TLS 模块。

您注意到 BodyReader 是一个 IO ByteString。但特别是它是一个可以重复的 Action ,每次都是下一个字节 block 。它遵循从不发送空字节串的协议(protocol),除非它位于文件末尾。 (BodyReader 可能被称为 ChunkGetter)。下面的 bip 就像你写的:从 Response 中提取 BodyReader/IO ByteString 后,它执行它获取第一个 block ,并打印它。但不会重复获得更多的 Action - 所以在这种情况下,我们只看到创世记的前几章。您需要的是一个循环来耗尽 block ,如下面的 bop 所示,这会导致整个 King James Bible 溢出到控制台中。

{-# 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

循环不断返回以获得更多 block ,直到它获得一个空字符串,它表示 eof,因此在终端中它打印到 Apocalypse 的末尾。

这是一种简单但略带技术性的行为。您只能通过手写递归来使用 BodyReader。但是 http-client 库的目的是使 http-conduit 之类的东西成为可能。结果是withResponse具有类型 Response (ConduitM i ByteString m ())ConduitM i ByteString m()是如何将一个字节流的conduit类型;这个字节流将包含整个文件。

http-client/http-conduit Material 的原始形式中,Response包含这样一个管道; BodyReader 部分后来被分解到 http-client 中,因此它可以被不同的流媒体库使用,例如 pipes

所以举个简单的例子,在对应的http资料中为streamingstreaming-bytestring图书馆,withHTTP为您提供 Response (ByteString IO ()) 类型的响应。 ByteString IO()顾名思义就是IO产生的字节流类型; ByteString Identity () 相当于惰性字节串(实际上是一个纯粹的 block 列表。)ByteString IO () 在这种情况下将代表整个字节流,直至启示录。所以随着进口

 import qualified Data.ByteString.Streaming.HTTP as Bytes -- streaming-utils
import qualified Data.ByteString.Streaming.Char8 as Bytes -- streaming-bytestring

该程序与惰性字节串程序相同:

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

实际上它稍微简单一些,因为您没有“从 IO 中提取字节”:

        lazy_bytes <- responseStatus response
Lazy.putStrLn lazy_bytes

但只是写

        Bytes.putStrLn $ responseBody response

您只需直接“打印”它们。如果你只想从 KJV 的中间看一点,你可以用惰性字节串做你想做的,并以:

        Bytes.putStrLn $ Bytes.take 1000 $ Bytes.drop 50000 $ responseBody response

然后你会看到一些关于亚伯拉罕的东西。

streaming-bytestringwithHTTP 只是隐藏了我们需要使用来自 http-client 的 BodyReader Material 的递归循环 直接。这是一样的,例如使用您在 pipes-http 中找到的 withHTTP , 表示一个字节串 block 流为Producer ByteString IO (),与http-conduit相同。在所有这些情况下,一旦您掌握了字节流,您就可以按照流式 IO 框架的典型方式处理它,而无需手写递归。它们都使用 http-client 中的 BodyReader 来执行此操作,这是该库的主要目的。

关于haskell - 为什么打印不强制整个惰性 IO 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41475255/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com