Как мне сделать автоматическую сериализацию данных объектов данных?
Одним из огромных преимуществ в языках, которые имеют своего рода отражение / интроспекцию, является то, что объекты могут автоматически создаваться из различных источников.
Например, в Java я могу использовать те же самые объекты для сохранения в БД (с Hibernate), сериализации в XML (с JAXB) и сериализации в JSON (json-lib). Вы можете сделать то же самое в Ruby и Python, обычно следуя некоторым простым правилам для свойств или аннотаций для Java.
Таким образом, мне не нужны лоты "Объекты передачи домена". Я могу сосредоточиться на области, в которой я работаю.
Кажется, в очень строгих FP, таких как Haskell и Ocaml, это невозможно. Особенно Haskell. Единственное, что я видел, - это какая-то предварительная обработка или метапрограммирование (ocaml). Просто принято, что вы должны делать все преобразования снизу вверх?
Другими словами, вам нужно проделать большую скучную работу, чтобы превратить тип данных в haskell в объект строки JSON/XML/DB и снова в объект данных.
5 ответов
Я думаю, что решение для препроцессора, найденное в OCaml (примером которого являются, помимо прочего, sexplib, binprot и json-wheel), довольно хорошо (и я думаю, что люди делают очень похожие вещи с шаблоном Haskell). Это гораздо более эффективно, чем отражение, и также может быть настроено на отдельные типы естественным образом. Если вам не нравится автоматически сгенерированный сериализатор для данного типа foo, вы всегда можете просто написать свой собственный, и он прекрасно вписывается в автоматически сгенерированные сериализаторы для типов, которые включают foo в качестве компонента.
Единственным недостатком является то, что вам нужно научиться camlp4, чтобы написать один из них для себя. Но использовать их довольно просто, если вы настроили систему сборки на использование препроцессора. Это так же просто, как добавление with sexp
до конца определения типа:
type t = { foo: int; bar: float }
with sexp
и теперь у вас есть ваш сериализатор.
Я не могу говорить с OCaml, но я бы сказал, что основная трудность в Haskell заключается в том, что десериализация требует знания типа заранее- нет универсального способа механической десериализации из формата, выяснения, каково полученное значение, и перейти оттуда, как это возможно в языках с ненадежными или динамическими системами типов.
Если оставить в стороне проблему с типом, существуют разные подходы к сериализации данных в Haskell:
Классы встроенного типа
Read
/Show
(де) сериализовать алгебраические типы данных и большинство встроенных типов в виде строк. Как правило, экземпляры с хорошим поведением должны быть такими, чтобыread . show
эквивалентноid
и что результатshow
может быть проанализирован как исходный код Haskell, создающий сериализованное значение.Различные пакеты сериализации можно найти на Hackage; обычно для этого требуется, чтобы сериализуемый тип был экземпляром некоторого класса типов, а пакет предоставляет экземпляры для большинства встроенных типов. Иногда они просто требуют автоматически выводимого экземпляра рефлексивного метапрограммирования с повторением типов
Data
класс (очаровательное полностью квалифицированное имя для которогоData.Data.Data
), или предоставьте код Template Haskell для автоматической генерации экземпляров.Для действительно необычных форматов сериализации - или для создания собственного пакета, подобного ранее упомянутым - можно достичь самого большого доступного молотка, своего рода "старшего брата", чтобы
Read
а такжеShow
: разбор и симпатичная печать. Для обоих доступно множество пакетов, и, хотя поначалу это может звучать пугающе, в Haskell синтаксический анализ и красивая печать на самом деле удивительно безболезненны.
Взгляд на Hackage указывает на то, что пакеты сериализации уже существуют для различных форматов, включая двоичные данные, JSON, YAML и XML, хотя я не использовал ни один из них, поэтому я не могу лично подтвердить, насколько хорошо они работают. Вот неполный список, с чего можно начать:
- двоичный: сериализация, ориентированная на производительность, до ленивых
ByteString
s - cereal: похож на бинарный, но немного другой интерфейс и использует строгий
ByteString
s - genericserialize: Сериализация с помощью встроенного метапрограммирования, формат вывода расширяемый, включает в себя вывод R5RS sexp.
- json: облегченная сериализация данных JSON
- RJson: сериализация в JSON с помощью встроенного метапрограммирования
- hexpat-pickle: комбинаторы для сериализации в XML с использованием пакета "hexpat"
- регулярный-xmlpickler: сериализация в XML рекурсивных структур данных с использованием "обычного" пакета
Единственная другая проблема заключается в том, что неизбежно не все типы будут сериализуемыми - если ничего другого, я подозреваю, вам будет трудно сериализовать полиморфные типы, экзистенциальные типы и функции.
Вы хотели
проделать большую скучную работу, чтобы превратить тип данных в haskell в объект строки JSON/XML/DB и снова обратно в объект данных.
В Haskell существует много способов сериализации и десериализации типов данных. Вы можете использовать, например,
а также другие распространенные форманты ( буфер протокола, thrift, xml)
Каждый пакет часто / обычно поставляется с макросом или механизмом получения, который позволяет вам, например, получить JSON. Для Data.Binary, например, см. Этот предыдущий ответ: Erlang's term_to_binary в Haskell?
Общий ответ таков: у нас есть много отличных пакетов для сериализации в Haskell, и мы склонны использовать существующую инфраструктуру "производных" классов (с универсальными или шаблонными макросами Haskell для фактического получения).
Обычный подход заключается в использовании Data.Binary. Это обеспечивает базовую возможность сериализации. Двоичные экземпляры для типов данных легко записываются и могут быть легко построены из небольших блоков.
Если вы хотите создать экземпляры автоматически, вы можете использовать Template Haskell. Я не знаю ни одного пакета для этого, но я не удивлюсь, если он уже существует.