通常导出大规模代数数据类型的任意?

car*_*emb 11 generics haskell quickcheck

我有一个我输入的协议:

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)
Run Code Online (Sandbox Code Playgroud)

另外,我已经为每个数据包实现了序列化/反序列化代码.当然,我想在Quickcheck中测试这个协议,并确保对任何输入组合的任何数据包进行序列化和反序列化都会让我准确地回复我所放入的内容.所以我继续为Arbitrary类型类实现这些数据包,如下所示:

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
    ...
Run Code Online (Sandbox Code Playgroud)

假设我已经完成并定义Arbitrary了所有没有Arbitrary开箱即用的相关数据构造函数参数,这些代码需要由我手工编写,以便使用有意义的数据填充数据包字段.但就是这样.

但正如你所看到的,我正在重复自己一些事情,这只是一些愚蠢的工作.这是我实际处理的一小部分样本.理想情况下,我希望能够做到这一点:

{-# 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
Run Code Online (Sandbox Code Playgroud)

就像我可以做FromJSONToJSON,但这不起作用.有没有一种方法呢?

car*_*emb 7

Daniel Wagner在评论中提到泛型随机能够做到这一点.这是我正在寻找的图书馆,但文档并没有让我明白这样的情况.在撰写本文时,Brent Yorgey在他的博客上发布了一个非常清晰的教程,详细介绍了如何generic-random用来做我所询问的内容等等.博客文章可以在这里找到.

就我而言,解决方案很简单.使用Generic.Random.Generic来自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
Run Code Online (Sandbox Code Playgroud)