2016-06-15 8 views
8

Ich habe ein Protokoll, die ich wie so eingegeben haben:Generisch abgeleitet Arbitrary für massive algebraische Datentypen?

data ProtocolPacket 
    = Packet1 Word8 Text Int8 
    | Packet2 Text 
    | Packet3 Int Text Text Text Text 
    | Packet4 Int Double Double Double Int16 Int16 Int16 
    ... 
    deriving (Show,Eq) 

Außerdem habe ich implementiert Serialisierung/Deserialisierung Code für jedes Paket. Natürlich möchte ich dieses Protokoll in Quickcheck testen und sicherstellen, dass das Serialisieren und Deserialisieren jedes Pakets für eine beliebige Kombination von Eingaben mir genau das zurückgibt, was ich eingegeben habe. Also fahre ich fort und implementiere diese Pakete für die Klasse Arbitrary wie folgt :

instance Arbitrary ProtocolPacket where 
    arbitrary = do 
    packetID <- choose (0x00,...) :: Gen Word8 
    case packetID of 
    0x00 -> do 
     a <- arbitrary 
     b <- arbitrary 
     c <- arbitrary 
     return $ Packet1 a b c 
    0x01 -> do 
     a <- arbitrary 
     return $ Packet2 a 
    0x02 -> do 
     a <- arbitrary 
     b <- arbitrary 
     c <- arbitrary 
     d <- arbitrary 
     e <- arbitrary 
     return $ Packet3 a b c d e 
    0x03 -> do 
     a <- arbitrary 
     b <- arbitrary 
     c <- arbitrary 
     d <- arbitrary 
     e <- arbitrary 
     f <- arbitrary 
     g <- arbitrary 
     return $ Packet4 a b c d e f g 
    ... 

wird angenommen, dass ich weiter und definiert Argumente Arbitrary für alle relevanten Daten Konstruktor gegangen sind, die Arbitrary aus der Box definiert nicht haben, einen solchen Code muss für die von mir, um von Hand geschrieben sein Paketfelder, die mit aussagekräftigen Daten gefüllt werden sollen. Aber das ist es.

Aber wie Sie sehen können, wiederhole ich mich viel für etwas, das nur grunzen Arbeit ist. Und das ist eine kleine Auswahl von dem, mit dem ich eigentlich zu tun habe. Im Idealfall würde Ich mag diese Lage sein, gerade zu tun:

{-# LANGUAGE DeriveGeneriC#-} 
import GHC.Generics 

data ProtocolPacket 
    = Packet1 Word8 Text Int8 
    | Packet2 Text 
    | Packet3 Int Text Text Text Text 
    | Packet4 Int Double Double Double Int16 Int16 Int16 
    ... 
    deriving (Show,Eq,Generic) 

instance Arbitrary ProtocolPacket 

wie ich mit FromJSON und ToJSON tun können, aber das funktioniert nicht. Gibt es eine Methode, die das tut?

+5

http://hackage.haskell.org/package/generic-random? –

+0

Hmm, ich sehe es gerade an. Es scheint in die Richtung zu gehen, die ich brauche. – carpemb

+2

Diese Funktion ist auch in [reguläre-extras] (https://hackage.haskell.org/package/regular-extras) verfügbar. Ich weiß nicht, wie es mit 'generic-random' verglichen wird. – dfeuer

Antwort

4

Daniel Wagner erwähnte in den Kommentaren, dass generic-random dazu in der Lage ist. Es war die Bibliothek, nach der ich suchte, aber die Dokumente machten mir nicht klar, dass dies der Fall war. Kürzlich veröffentlichte Brent Yorgey ein ziemlich klares Tutorial in seinem Blog, in dem ausführlich erläutert wurde, wie man generic-random verwenden kann, um das zu tun, wonach ich gefragt habe und mehr. The blog post can be found here.

Für meinen Fall ist die Lösung einfach. Mit Generic.Random.Generic von generic-random:

{-# LANGUAGE DeriveGeneriC#-} 
import Generic.Random.Generic 
import GHC.Generics 

data ProtocolPacket 
    = Packet1 Word8 Text Int8 
    | Packet2 Text 
    | Packet3 Int Text Text Text Text 
    | Packet4 Int Double Double Double Int16 Int16 Int16 
    ... 
    deriving (Show,Eq,Generic) 

instance Arbitrary ProtocolPacket where 
    arbitrary = genericArbitrary