2010-04-22 2 views
15

Uno degli enormi vantaggi dei linguaggi che hanno una sorta di riflessione/introspeczione è che gli oggetti possono essere costruiti automaticamente da una varietà di fonti.Come si esegue la serializzazione automatica dei dati degli oggetti dati?

Ad esempio, in Java è possibile utilizzare gli stessi oggetti per mantenere un db (con Hibernate), serializzarlo su XML (con JAXB) e serializzare su JSON (json-lib). Puoi fare lo stesso anche in Ruby e Python, seguendo di solito alcune semplici regole per le proprietà o le annotazioni per Java.

Quindi non ho bisogno di molti "oggetti di trasferimento domini". Posso concentrarmi sul dominio in cui lavoro.

Sembra in FP molto rigido come Haskell e Ocaml questo non è possibile. In particolare Haskell. L'unica cosa che ho visto è fare una sorta di pre-elaborazione o meta-programmazione (ocaml). È solo accettato che tu debba fare tutte le trasformazioni dal basso verso l'alto?

In altre parole, è necessario eseguire molte operazioni noiose per trasformare un tipo di dati in haskell in un oggetto riga JSON/XML/DB e di nuovo in un oggetto dati.

+0

"in rigorose FP [lingue] [..] questo non è possibile" - i problemi che si verificano non sono causati dalla programmazione funzionale, ma da altre funzionalità/limitazioni di Haskell/OCaml. –

+0

Abbastanza giusto. Avrei dovuto dire lingue algebriche di tipo compile sicuro. Sì, in qualcosa come Lisp questo probabilmente non è un problema. La definizione di FP severa è un po 'allentata. Anche con linguaggi come Scala in cui si ha una riflessione, l'approccio preferito è "analizzare" i dati (vedere anorm per giocare 2). –

+0

Anche @mattfenwick Non sono sicuro che mi piacciono le tue modifiche se rimuovi Haskell dal titolo e rovini google. Questo no –

risposta

4

Per quello che vale, penso che la soluzione di pre-processore trovata in OCaml (come esemplificato da sexplib, binprot e json-wheel, tra gli altri) sia piuttosto grande (e penso che le persone facciano cose molto simili con Template Haskell). È molto più efficiente della riflessione e può anche essere sintonizzato su singoli tipi in modo naturale. Se non ti piace il serializzatore generato automaticamente per un dato tipo foo, puoi sempre scrivere il tuo e si adatta perfettamente ai serializzatori generati automaticamente per i tipi che includono foo come componente.

L'unico svantaggio è che è necessario imparare camlp4 per scrivere uno di questi per te. Ma usarli è abbastanza facile, una volta che hai configurato il tuo sistema di build per usare il preprocessore. E 'semplice come l'aggiunta with sexp alla fine di una definizione di tipo:

type t = { foo: int; bar: float } 
with sexp 

e ora avete il vostro serializzatore.

+0

dovrò dare un'occhiata più da vicino a sexplib grazie :) –

4

La mia comprensione è che il modo più semplice per serializzare e deserializzare in Haskell è derivare da Read e Show. Questo è semplice e non soddisfa le tue esigenze.

Tuttavia ci sono HXT e Text.JSON che sembrano fornire quello che ti serve.

27

non posso parlare di OCaml, ma direi che la difficoltà principale in Haskell è che deserializzazione richiede la conoscenza del tipo in anticipo --Ci c'è modo universale per deserializzare meccanicamente da un formato, capire cosa il valore risultante è, e va da lì, come è possibile nelle lingue con sistemi di tipo non corretto o dinamico.

Mettendo da parte la questione di tipo, ci sono vari approcci per la serializzazione dei dati in Haskell:

  • Il built-in classi di tipo Read/Show (de) serializzare i tipi di dati algebrici e più tipi predefiniti come stringhe. Le istanze ben educate dovrebbero generalmente essere tali che read . show è equivalente a id e che il risultato di show può essere analizzato come codice sorgente Haskell che costruisce il valore serializzato.

  • Vari pacchetti di serializzazione possono essere trovati su Hackage; in genere questi richiedono che il tipo da serializzare sia un'istanza di una classe di tipo, con il pacchetto che fornisce le istanze per la maggior parte dei tipi incorporati. A volte richiedono semplicemente un'istanza derivabile automaticamente del tipo reificante, metaprogrammazione riflessiva della classe Data (l'affascinante nome completo qualificato per il quale è Data.Data.Data) o fornire il codice Template Haskell per generare automaticamente le istanze.

  • Per i formati di serializzazione veramente inusuali - o per creare il proprio pacchetto come quelli menzionati in precedenza - si può raggiungere per il più grande martello a disposizione, una sorta di "grande fratello" per Read e Show: l'analisi e la pretty- stampa. Numerosi pacchetti sono disponibili per entrambi e, anche se all'inizio potrebbe sembrare intimidatorio, l'hashing e la pretty-printing sono in effetti incredibilmente indolori in Haskell.

Uno sguardo alla Hackage indica che esistono già dei pacchetti di serializzazione di vari formati, inclusi dati binari, JSON, YAML, e XML, anche se non ho usato nessuna di loro quindi non posso personalmente testimoniare come bene funzionano. Ecco un elenco non esaustivo per iniziare:

  • binary: performance-oriented serializzazione a pigro ByteString s
  • cereal: Simile a binario, ma un'interfaccia leggermente diversa e utilizza rigorosa ByteString s
  • genericserialize : Serializzazione tramite metaprogrammazione incorporata, il formato di output è estensibile e include l'uscita sexp R5RS.
  • json: serializzazione leggero dei dati JSON
  • RJson: serializzazione a JSON tramite built-in metaprogrammazione
  • hexpat-pickle: combinatori per la serializzazione di XML, utilizzando il pacchetto "hexpat"
  • regular-xmlpickler: serializzazione XML di ricorsiva strutture di dati che utilizzano il pacchetto "regolare"

L'unico altro problema è che, inevitabilmente, non tutti i tipi saranno serializzabili - se non altro, ho il sospetto che avrete un d time serializzando tipi polimorfi, tipi esistenziali e funzioni.

+0

Grazie per tutte le informazioni. Volevo davvero darti la risposta corretta ma cercavo più "automatico" e sembra che tu debba fare il pre-trattamento. –

+5

@Adam Gent: Beh, per quello che posso dire, i pacchetti che utilizzano la metaprogrammazione generica incorporata sono quasi automatici, che richiedono solo istanze di 'Data' e/o' Typeable', che possono essere derivati ​​automaticamente da GHC . Tutto ciò che è richiesto è una clausola 'derivante (Data, tipizzabile)' aggiunta a qualsiasi definizione 'data' /' newtype', allo stesso modo in cui spesso si usano istanze derivate automatiche per 'Show',' Eq', ecc. –

+0

Darn perché può posso dare a due persone la risposta giusta! Sì, i tuoi esempi sembrano buoni. –

3

L'approccio abituale è quello di utilizzare Data.Binary. Questo fornisce la capacità di serializzazione di base. Le istanze binarie per i tipi di dati sono facili da scrivere e possono essere facilmente ricavate da unità più piccole.

Se si desidera generare automaticamente le istanze, è possibile utilizzare Template Haskell. Non conosco alcun pacchetto per farlo, ma non sarei sorpreso se ne esiste già uno.

4

per eseguire molte operazioni noiose per trasformare un tipo di dati in haskell in oggetto riga JSON/XML/DB e di nuovo in un oggetto dati.

Esistono molti modi per serializzare e unserializzare i tipi di dati in Haskell.È possibile utilizzare, ad esempio,

così come altri formanti comuni (protocol buffers, thrift, xml)

Ogni pacchetto spesso/di solito viene fornito con una macro o meccanismo derivante per consentire ad es derivare JSON. Per esempio, per Data.Binary: Erlang's term_to_binary in Haskell?

La risposta generale è: abbiamo molti grandi pacchetti per la seralizzazione in Haskell e tendiamo a utilizzare l'infrastruttura di derivazione della classe esistente (con genreics o template haskell macro per fare l'effettivo derivante).