Haskell中的ByteStrings:我应该使用Put还是Builder?

mk1*_*k12 10 monads haskell functional-programming binary-data

我对Putmonad提供的Builder直接使用内容感到困惑Data.Binary.我阅读了处理二进制数据的二进制生成部分,它似乎假设您应该使用Put,但它很短并不能解释原因.

Data.Binary.Put

Put monad.一个有效构造惰性字节串的monad.

type Put = PutM ()
Run Code Online (Sandbox Code Playgroud)

只需将Builder升级为Writer monad,应用于().

Data.Binary.Builder

高效构造惰性字节串.


什么是点Writer单子应用()

我可以看到它Put是(一个类型的同义词)monad而Builder不是,但我真的不明白为什么Put需要.

在我的例子中,我正在渲染3D场景并将每个像素写为3个字节,然后将PPM格式的标题添加到开头(之后将使用PNG).

Binary似乎它是为了可以对二进制数据进行序列化和反序列化的类型进行实例化.这不完全是我正在做的事情,但是Binary为我的颜色类型实例化感觉很自然

instance (Binary a) => Binary (Colour a) where
    put (Colour r g b) = put r >> put g >> put b
    get = Colour <$> get <*> get <*> get
Run Code Online (Sandbox Code Playgroud)

这可以很容易地putColour Word8到24位.但是接下来我还要抓住标题,我不知道该怎么做.

Builder隐藏在幕后,还是依赖于它?是Binary类只对(反)序列数据,或所有二进制代的目的呢?

小智 11

首先要注意概念上的差异.构建器用于高效构建字节串流,而PutMmonad实际上用于序列化.所以你应该问自己的第一个问题是你是否真的在序列化(回答问自己是否有一个有意义且完全相反的操作 - 反序列化).

一般来说,我会选择Builder它提供的便利.但是,不是Builder来自二进制包,而是来自blaze-builder包.它是一个monoid并且有许多预定义的字符串生成器.它也非常易于组合.最后它非常快,实际上可以进行微调.

最后但并非最不重要的是,如果您真的想要速度,便利和优雅的代码,您将需要将其与各种流处理器库之一(如管道,枚举器管道)相结合.


Dan*_*her 10

我可以看到这Put是一个单子而Builder不是,但我真的不明白为什么Put需要它.

确切地说,PutMMonad.这是为了方便起见,并为您提供更少的错误机会.以monadic或applicative样式编写代码通常比明确地携带所有临时代码更方便,并且在Monad实例中完成管道,您不能Builder在函数中间意外使用错误.

你可以PutM只使用你所做的一切Builder,但通常编写代码的工作量更大.

但是接下来我还要抓住标题,我不知道该怎么做.

我不知道PPM格式,所以我不知道如何构造标题.但是在构建它之后,你可以简单地使用putByteString或者putLazyByteString解决它.