对于大量的代数数据类型,一般以任意方式导出? [英] Generically derive Arbitrary for massive algebraic data types?
问题描述
我输入的协议如下:
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)
此外,我已经为每个数据包实现了序列化/反序列化代码.自然,我想在Quickcheck中测试此协议,并确保对任何输入组合的数据包进行序列化和反序列化将完全返回我所输入的内容.因此,我继续为Arbitrary
类型类实现这些数据包像这样:
In addition, I've implemented serialization/deserialization code for each packet. Naturally, I would like to test this protocol in Quickcheck and make sure that serializing and deserializing any packet for any combination of inputs will give me back exactly what I put in. So I go ahead and implement these packets for the Arbitrary
type class like so:
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
...
假设我已经为所有未定义的Arbitrary
的相关数据构造函数自变量定义了Arbitrary
,则此类代码需要由我手写以用于数据包要填充有意义的数据的字段.就是这样.
Assume that I've gone ahead and defined Arbitrary
for all relevant data constructor arguments that don't have Arbitrary
defined out of the box, such code needs to be hand-written by me in order for the packet fields to be populated with meaningful data. But that's it.
但是,正如您所看到的,我要重复自己很多,因为这只是艰苦的工作.这只是我实际处理的一小部分.理想情况下,我希望能够做到这一点:
But as you can see, I'm repeating myself a lot for something that is just grunt work. And this is a small sample of what I'm actually dealing with. Ideally, I would like to be able to just do this:
{-# 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
就像我可以使用FromJSON
和ToJSON
一样,但这不起作用.有没有可以的方法?
like I can do with FromJSON
and ToJSON
, but this doesn't work. Is there there a method that does?
推荐答案
Daniel Wagner在评论中提到 generic-random 可以做到这一点.那是我一直在寻找的库,但是文档对我而言并不明显.最近,Brent Yorgey在他的博客上发布了一个非常清晰的教程,其中详细介绍了如何使用generic-random
来完成我所要询问的内容以及更多内容. 博客帖子可以在这里找到.
Daniel Wagner mentioned in the comments that generic-random is capable of doing this. It was the library I was looking for, but the docs didn't make it obvious to me that such was the case. Recent to the time of this writing, Brent Yorgey posted a pretty clear tutorial on his blog that went into detail as to how to use generic-random
to do what I was asking about and more. The blog post can be found here.
就我而言,解决方案很简单.使用generic-random
中的Generic.Random.Generic
:
For my case, the solution is simple. Using Generic.Random.Generic
from 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
这篇关于对于大量的代数数据类型,一般以任意方式导出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!