ByteStrings в Haskell: следует ли использовать Put или Builder?
Я смущен тем, что монада Put
предлагает с помощью Builder
напрямую, в Data.Binary
. Я прочитал раздел Binary Generation в разделе "Работа с двоичными данными", и, похоже, вы должны использовать Put
, но он довольно короткий, t объясните почему.
Data.Binary.Put
Монаха Пута. Монада для эффективного построения ленивых байтов.
type Put = PutM ()
Поместите просто подъемник Builder в монадию писателя, применимую к().
Data.Binary.Builder
Эффективное построение ленивых байтовых строк.
Какова точка монады Writer
, примененной к ()
?
Я вижу, что Put
(синоним типа) монады, тогда как 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
Это упрощает Put
a Colour Word8
до 24 бит. Но тогда я также должен придерживаться заголовка, и я не уверен, как это сделать.
Является ли Builder
скрытым за кулисами или зависит от этого? Является ли класс Binary
только для (де) сериализации данных или для всех целей генерации двоичных данных?
Ответы
Ответ 1
Прежде всего обратите внимание на концептуальную разницу. Строители предназначены для эффективного построения потоковых потоков, в то время как монада PutM
действительно предназначена для сериализации. Поэтому первый вопрос, который вы должны задать себе, заключается в том, действительно ли вы сериализуете (чтобы ответить, спрашивайте себя, есть ли значимая и точная противоположная операция - десериализация).
В общем, я бы пошел с Builder
для удобства, которое он предоставляет. Однако не Builder
из двоичного пакета, а на самом деле из пакета blaze-builder. Это моноид и имеет множество предопределенных генераторов строк. Это также очень сложно. Наконец, это очень быстро и на самом деле можно точно настроить.
И последнее, но не менее важное: если вы действительно хотите скорость, удобство и элегантный код, вы захотите объединить это с одной из различных библиотек потоков, таких как кабелепровод, перечислитель или каналы.
Ответ 2
Я вижу, что Put
является монадой, тогда как Builder
не является, но я действительно не понимаю, зачем понадобилось Put
.
Если быть точным, PutM
- это Monad
. Это необходимо для удобства и предоставить вам меньше возможностей для ошибок. Написание кода в монадическом или аппликативном стиле часто намного удобнее, чем перенос всех временных ячеек в явном виде, и с помощью сантехники, выполненной в экземпляре Monad
, вы не можете случайно использовать неправильный Builder
в середине вашей функции.
Вы можете делать все, что вы делаете, с помощью PutM
, используя только Builder
, но обычно это больше работает для написания кода.
Но тогда я также должен придерживаться заголовка, и я не уверен, как это сделать.
Я не знаю формат PPM, поэтому я понятия не имею, как построить заголовок. Но после его построения вы можете просто использовать putByteString
или putLazyByteString
для его включения.
Ответ 3
Я не уверен, насколько это точно, но мое понимание всегда заключалось в том, что презентация Put
, как вы видите, во многом является злоупотреблением do-notation, так что вы можете написать код следующим образом:
putThing :: Thing -> Put
putThing (Thing thing1 thing2) = do
putThing1 thing1
putThing2 thing2
Мы не используем "сущность" Monad
(в частности, мы никогда не связываем результат чего-либо), но мы получаем удобный и чистый синтаксис для конкатенации. Однако эстетические преимущества по сравнению с чисто моноидальной альтернативой:
putThing :: Thing -> Builder
putThing (Thing thing1 thing2) = mconcat [
putThing thing1,
putThing thing2]
на мой взгляд, довольно минимальны.
(Обратите внимание, что Get
, напротив, действительно является Монадой и выигрывает от ясного понимания).