Andrey Kachow
Andrey Kachow

Reputation: 1126

Shuffling a list using random-fu shuffle, doing an operation on a list and displaying result in Haskell

My goal is to get a list of N random items taken from an input list and see the result in GHCI. I decided to shuffle the input list, then take the first N elements from it (i.e. slice first elements). I am using shuffle function from random-fu module Data.Random.List.

Here's the code I currently have and at least it can be compiled

import Data.Random
import Data.Random.List

rndSelect :: [a] -> Int -> RVar [a]
rndSelect l n
  = do 
       l' <- shuffle l;
       return $ take n l'

But when I run rndSelect "abcdefg" 3 in GHCI prompt, I get the following error:

<interactive>:1:1: error:
    • No instance for (Show (RVar [Char]))
        arising from a use of ‘print’
    • In a stmt of an interactive GHCi command: print it

I think I know what it means. RVar doesn't derive Show. I guess I should modify my function so that it gets shuffled RVar[a] and then somehow take a list of the first N elements and convert it to IO action.

Here's one of my failed attempts:

rndSelect :: [a] -> Int -> IO ()
rndSelect l n
  = do 
       l' <- shuffle l;
       l'' <- take n l'
       s <- runRVar l'' StdRandom
       putStrLn s

I know, that it is messed up and raises errors on top of errors. I am beginner in Monads, "do" blocks and things like that in Haskell

I would be glad if someone help me to fix my approach, but if you know alternative way to achieve my goal, I will be happy to see it as well. Thank you very much!

Upvotes: 1

Views: 106

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120741

Your rndSelect :: [a] -> Int -> RVar [a] is perfectly fine, but it should be obvious that the resulting RVar [a] can't really be shown. After all, this is a probability distribution. Such distributions “contain” in general infinitely many possible outcomes. All you can hope to do is to show samples from the distribution. Since GHCi allows you to do IO, it's easy to obtain samples right there:

*Main> sample $ rndSelect "abcdefg" 3
"def"
*Main> sample $ rndSelect "abcdefg" 3
"ecb"
*Main> sample $ rndSelect "abcdefg" 3
"fbc"
*Main> :m +Control.Monad
*Main Control.Monad> sample . replicateM 20 $ rndSelect "abcdefg" 3
["gef","adf","cga","bfd","eab","bgd","gdf","abg","egc","bda","ceb","fbd","agb","egc","acb","bga","gbd","edb","egb","egd"]

Upvotes: 2

Related Questions