2016-06-15 11 views
8

Tôi đã có một giao thức mà tôi đã gõ như sau:Một cách tự nhiên có được tùy ý cho các kiểu dữ liệu đại số lớn?

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) 

Ngoài ra, tôi đã triển khai mã serialization/deserialization cho mỗi gói. Đương nhiên, tôi muốn kiểm tra giao thức này trong Quickcheck và đảm bảo rằng việc tuần tự hóa và deserializing bất kỳ gói nào cho bất kỳ kết hợp đầu vào nào cũng sẽ trả lại chính xác những gì tôi đưa vào. Vì vậy, tôi tiếp tục và triển khai các gói này cho lớp loại 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 
    ... 

Giả sử rằng tôi đã đi trước và định nghĩa Arbitrary cho tất cả các đối số nhà xây dựng dữ liệu có liên quan mà không có Arbitrary định nghĩa ra khỏi hộp, mã như vậy cần phải được viết tay của tôi để cho các trường gói được điền với dữ liệu có ý nghĩa. Nhưng kia là nó.

Nhưng như bạn có thể thấy, tôi lặp lại bản thân mình rất nhiều cho điều gì đó chỉ là công việc lùn. Và đây là một mẫu nhỏ về những gì tôi thực sự đang xử lý. Lý tưởng nhất, tôi muốn có thể chỉ cần làm điều này:

{-# 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 

như tôi có thể làm gì với FromJSONToJSON, nhưng điều này không hoạt động. Có phương pháp nào không?

+5

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

+0

Hmm, tôi đang xem nó ngay bây giờ. Nó dường như đang đi theo hướng tôi cần. – carpemb

+2

Chức năng này cũng có sẵn trong [tính năng bổ sung thông thường] (https://hackage.haskell.org/package/regular-extras). Tôi không biết nó so sánh với 'generic-random' như thế nào. – dfeuer

Trả lời

4

Daniel Wagner đã đề cập trong các nhận xét rằng generic-random có khả năng thực hiện việc này. Đó là thư viện mà tôi đang tìm kiếm, nhưng các tài liệu không cho tôi thấy rõ ràng như vậy. Gần đây đến thời điểm viết bài này, Brent Yorgey đã đăng một hướng dẫn khá rõ ràng trên blog của anh ta đã đi vào chi tiết như thế nào để sử dụng generic-random để làm những gì tôi đã hỏi về và nhiều hơn nữa. The blog post can be found here.

Đối với trường hợp của tôi, giải pháp rất đơn giản. Sử dụng Generic.Random.Generic từ 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 
Các vấn đề liên quan