2015-08-10 10 views
7

ho qualcosa simile al seguenteMaybes obbligatori nel sistema di tipo

data A = A 
    { id :: Integer 
    , foo :: Maybe String 
    , bar :: Maybe String 
    , baz :: Maybe String 
    } 

Questi dati è in arrivo al mio servizio come JSON. Questa richiesta è considerata valida solo se vengono forniti uno o più numeri di foo, bar o baz. Esiste un modo migliore per esprimere ciò nel sistema di tipi di Haskell?

Nota: Purtroppo non riesco a fare richieste separate. Sto solo seguendo un protocollo definito.

+1

Cosa sono 'foo',' bar' e 'baz'? Qual è la relazione tra questi tre? – Shoe

+0

Sono diversi tipi di "impressioni" che possono entrare nel servizio. 'Banner',' Video', 'Nativo'. Ognuno di loro descrive un diverso tipo di impressione su cui possono fare offerte. Sto cercando di implementare le specifiche OpenRTB in Haskell. –

+1

possibile duplicato di [Esiste un tipo haskell canonico per "Uno o entrambi"?] (Http://stackoverflow.com/questions/19413438/is-there-a-canonical-haskell-type-for-one-or- entrambi) – jberryman

risposta

11

http://hackage.haskell.org/package/these-0.4.2/docs/Data-These.html

import Data.These 
data A = A 
    { id :: Integer 
    , fooBarBaz :: These Foo (These Bar Baz) 
    } 

type Foo = String 
type Bar = String 
type Baz = String 
+9

Forse include una breve spiegazione invece del solo codice e un link di riferimento. –

+2

No, è esattamente come dovrebbe essere. – MigMit

+1

Esiste anche una versione minimalista di 'These' in [' data-or'] (https://hackage.haskell.org/package/data-or). – duplode

4

vorrei usare un Map Field String con data Field = Foo | Bar | Baz (questo può essere facilmente sostituito con String, se necessario, e poi:

data A = A 
    { id :: Integer 
    , fields :: Map Field String 
    } 

Ora il controllo per la condizione di validità è semplice come:

isValid :: A -> Bool 
isValid = not . Map.null . fields 
4

Se non è obbligatorio avere tre campi separati con foo, bar e baz, vorrei andare con questo, NonEmpty garantisce che ci sia almeno un elemento, anche se ovviamente può essercene di più.

import Data.List.NonEmpty 

data Impression = Banner String | Video String | Native String 

data A = A 
    { id :: Integer 
    , fooBarBaz :: NonEmpty Impression 
    } 
2

considerazione dando un ramo per ogni possibile campo obbligatorio:

data A 
    = Foo 
     { foo :: String 
     , barM, bazM :: Maybe String 
     } 
    | Bar 
     { bar :: String 
     , fooM, barM :: Maybe String 
     } 
    | Baz 
     { baz :: String 
     , fooM, barM :: Maybe String 
     } 

E 'un bel po' di boilerplate, ma è molto diretto e abbastanza chiaro su ciò che è richiesto.

Problemi correlati