获取Data.ByteString.Builder的长度

时间:2014-10-21 17:00:06

标签: haskell

我有一个函数tabulate,它接受​​一个对象列表,以及一个将这些对象的字段转换为Builders的函数列表。它返回一个表示格式良好的表的Builder。 E.g:

tabulate :: [a -> Builder] -> [a] -> Builder
tabulate = ...
data Assc = Assc { key :: String, value :: String }

> let funcs = [string7 . key, const $ char7 '=', string7 . value ]
> let objs = ["short" `Assc` "a", "longer" `Assc` "b", "waylongername" `Assc` "c"]
> hPutBuilder stdout $ tabulate funcs objs
short         = a
longer        = b
waylongername = c

为此,我需要确定每列的最大长度。目前我在每个元素上使用toLazyByteString(这太慢了)。

是否有可能在没有先将Builder变为ByteString的情况下获得tabulate的长度?

或者,是否存在(有效)实施Builder的另一种方式(使用或不使用{{1}})?

1 个答案:

答案 0 :(得分:5)

查看Builder的来源,将其定义为

newtype Builder = Builder (forall r. BuildStep r -> BuildStep r)

因此,排序Builder只是组成函数,如果不评估函数堆栈,就无法获得输出的长度。但是你可以创建一个自己的帮助器模块,其数据类型可以将Builder与长度计算结合起来:

newtype BuilderL = BuilderL { blLenght :: !Int, blBuilder :: Builder }

instance Monoid BuilderL where
    mempty = BuilderL 0 mempty
    mappend (BuilderL l1 t1) (BuilderL l2 t2) = BuilderL (l1 + l2) (t1 <> t2)

然后创建辅助函数来构造BuilderL s,比如

byteString :: ByteString -> BuilderL
byteString t = BuilderL (length t) (byteString t)

等。然后使用此模块和BuilderL作为您的表格,您将始终掌握所需的长度。

相关问题