gpt4 book ai didi

haskell - 吃我的麦片并解析它

转载 作者:行者123 更新时间:2023-12-03 15:06:42 25 4
gpt4 key购买 nike

我正在使用 Data.Serialize.Get并尝试定义以下组合器:

getConsumed :: Get a -> Get (ByteString, a)

应该像传入的 Get操作,还返回 ByteStringGet消耗。用例是我有一个二进制结构,我需要解析和散列,并且在解析之前我不知道长度。

这个组合器尽管语义简单,但实现起来却出奇的棘手。

无需深入研究 Get 的内部结构,我的直觉是使用这个怪物:
getConsumed :: Get a -> Get (B.ByteString, a)
getConsumed g = do
(len, r) <- lookAhead $ do
before <- remaining
res <- g
after <- remaining
return (before - after, res)
bs <- getBytes len
return (bs, r)

它将使用前瞻,在运行 Action 之前和之后查看剩余字节,返回 Action 结果,然后消耗长度。这不应该重复任何工作,但它偶尔会失败:
*** Exception: GetException "Failed reading: getBytes: negative length requested\nEmpty call stack\n"

所以我一定是在某个地方误解了一些关于 Cereal 的事情。

有人看到我对 getconsumed 的定义有什么问题吗?或者对如何实现它有更好的想法?

编辑:Dan Doel 指出 remaining可以只返回给定 block 的剩余长度,如果您跨越 block 边界,这不是很有用。在这种情况下,我不确定该操作的重点是什么,但这解释了为什么我的代码不起作用!现在我只需要找到一个可行的替代方案。

编辑 2:再想一想之后,似乎 remaining如果我提供 Get,则给我当前 block 的长度可能对我有利在循环中手动使用单个 block ( remaining >>= getBytes),并在我这样做时跟踪它正在吃什么。我还没有设法使这种方法起作用,但它似乎比原来的方法更有希望。

编辑 3:如果有人好奇,这里是上面编辑 2 的代码:
getChunk :: Get B.ByteString
getChunk = remaining >>= getBytes

getConsumed :: Get a -> Get (B.ByteString, a)
getConsumed g = do
(len, res) <- lookAhead $ measure g
bs <- getBytes len
return (bs, res)
where
measure :: Get a -> Get (Int ,a)
measure g = do
chunk <- getChunk
measure' (B.length chunk) (runGetPartial g chunk)

measure' :: Int -> Result a -> Get (Int, a)
measure' !n (Fail e) = fail e
measure' !n (Done r bs) = return (n - B.length bs, r)
measure' !n (Partial f) = do
chunk <- getChunk
measure' (n + B.length chunk) (f chunk)

不幸的是,一段时间后我的示例输入似乎仍然失败:
*** Exception: GetException "Failed reading: too few bytes\nFrom:\tdemandInput\n\n\nEmpty call stack\n"

最佳答案

编辑:另一个解决方案,没有额外的计算!

getConsumed :: Get a -> Get (B.ByteString, a)
getConsumed g = do
(len, r) <- lookAhead $ do
(res,after) <- lookAhead $ liftM2 (,) g remaining
total <- remaining
return (total-after, res)
bs <- getBytes len
return (bs, r)

一种解决方案是调用 lookAhead两次。第一次确保加载所有必要的 block ,第二次执行实际长度计算(以及返回反序列化数据)。
getConsumed :: Get a -> Get (B.ByteString, a)
getConsumed g = do
_ <- lookAhead g -- Make sure all necessary chunks are preloaded
(len, r) <- lookAhead $ do
before <- remaining
res <- g
after <- remaining
return (before - after, res)
bs <- getBytes len
return (bs, r)

关于haskell - 吃我的麦片并解析它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11424961/

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