Skip to the content.

Writing an instance of Arbitrary for a list

Imagine you have two functions which convert Word32 to its bit representation and vise versa. These functions would be something like this.

toBits :: Word32 -> [Bool]
toBits = ...

fromBits :: [Bool] -> Word32
fromBits = ...

Their implementations are trivial, but I’d like to write tests for them. With doctest, you can write QuickCheck properties for them as comments.

I’m going to write two properties; one of them is that fromBit (toBit n) == n and the other is toBit (fromBit bits) == bits. You can write the former easily.

-- |
-- prop> \n -> fromBits (toBits n) == (n :: Word32)
toBits :: Word32 -> [Bool]
toBits = ...

But the latter is not that simple because we have to restrict QuickCheck to generate lists of Bool which is no longer than 32 in its length. To do that, I cannot use the default instance of Arbitrary for a list. Instead, I need to define its newtype wrapper by ourselves.

With doctest, I can write these declarations in $setup named chunk.

-- $setup
-- >>> import Test.QuickCheck
-- >>>
-- >>> newtype Bits = Bits { getBits :: [Bool] } deriving Show
-- >>> instance Arbitrary Bits where arbitrary = Bits <$> resize (finiteBitSize (undefined :: Word32)) arbitrary

I’m using resize to tell a generator to generate lists which is no longer than 32. With this instance, I can write the property like this.

-- |
-- prop> \bits -> toBits (fromBits (getBits bits) :: Word32) == getBits bits
fromBits :: [Bool] -> Word32
fromBits = ...