[Haskell-cafe] Re: Random question

Brent Yorgey byorgey at seas.upenn.edu
Tue Oct 7 14:16:15 EDT 2008


On Tue, Oct 07, 2008 at 06:40:22PM +0100, Iain Barnett wrote:
> On 5 Oct 2008, at 7:06 pm, Henning Thielemann wrote:
>>
>> Instead of separate calls to 'take' and 'drop' you may prefer 'splitAt':
>>
>>  requeue z xs =
>>     let (prefix,pivot:suffix) = splitAt (z-1) xs
>>     in  prefix ++ suffix ++ [pivot]
>
> Thanks. Took me a while to get the function to shuffle properly again, but
>
> shuffle xs = shuffle' (length xs) xs
>
> shuffle' :: Int -> [a] -> IO [a]
> shuffle' 0 xs = return xs
> shuffle' (len + 1) xs = rand 0 len >>= \r -> shuffle' len $ requeue r xs
>     where requeue z ys = let (prefix,pivot:suffix) = splitAt z ys
>                          in prefix ++ suffix ++ [pivot]
>
> *Main> shuffle [11..18]
> [14,11,13,16,12,15,18,17]
>
> *Main> shuffle [11..18]
> [16,13,12,11,17,14,18,15]
>
>
> Until I master Quickcheck, that will do for me :)

Using QuickCheck is actually pretty easy.  It's made more difficult in
this particular case since the result of your shuffle function is in
the IO monad.  But assuming you split out the shuffling functionality
into a pureShuffle function which takes a random seed as an extra
parameter, you could make a property to test it as follows:

prop_shuffle :: Seed -> Seed -> [a] -> Bool
prop_shuffle s1 s2 l = sort (pureShuffle s1 l) == sort (pureShuffle s2 l)

Then you could test it by evaluating 'quickCheck prop_shuffle' at a
ghci prompt.  Nice and simple!

-Brent


More information about the Haskell-Cafe mailing list