Search code examples
listhaskellquickcheck

Generate a list that is garanteed to have a 7 in it


How do I do this? I want something with the structure sevenList :: Gen [Integer] that generates a list and that is guaranteed to always include at least one 7.

I know that if I wanted to generate a list of size n, I could do something like this:

listOfLength n gen = sequence [ gen | i <- [1..n] ]

But this is not sufficient because if I for example generate a list of length 10 and a 7 is not generated I have to continue, but at the moment it wont.


Solution

  • You can decide to generate two lists, and then construct a list where we append the lists with a seven sandwiched between them.

    For instance:

    genSevenList :: Gen [Integer]
    genSevenList = do
        la <- arbitrary
        lb <- arbitrary
        return $ la ++ 7 : lb
    

    The first two statements thus generate two arbitrary [Integer] lists, and then we return $ la ++ 7 : lb. We thus prepend lb with 7, and append this to la.

    You can also generate one arbitrary list, split it at a random index and then join these parts together as described above. For instance:

    genSevenList :: Gen [Integer]
    genSevenList = do
        l <- arbitrary
        k <- choose (0,length l)
        let (la,lb) = splitAt k l
        return $ la ++ 7 : lb
    

    Although both are capable of generating all possible lists, like @leftroundabout says, it is more likely that the second implementation will come up with shorter lists, since the odds that both aribtrary calls will generate a short list (or an empty list) is not that large.