# Picking a card from a shuffled deck

I'm pretty new to Haskell although I did some ML many moons ago.

I'm trying to set up a deck of playing cards, shuffle them and then deal them. I have the deck and shuffle sorted (of a fashion) but I'm not sure what I'm doing after that.

This is what I have so far:

``````import System.Random
import Data.Array.IO

-- | Randomly shuffle a list
--   /O(N)/
shuffle :: [a] -> IO [a]
shuffle xs = do
ar <- newArray n xs
forM [1..n] \$ \i -> do
j <- randomRIO (i,n)
writeArray ar j vi
return vj
where
n = length xs
newArray :: Int -> [a] -> IO (IOArray Int a)
newArray n xs =  newListArray (1,n) xs

ranks=[2..14]

suits=[1,2,3,4]

cards=[(r,s) | r <- ranks, s<- suits]

deck=shuffle cards

myAction :: IO [(Integer, Integer)]
myAction = shuffle cards

main :: IO ()
main = do
xs <- myAction
print xs
``````

There was no particular reason I chose that list shuffler other than the reason I could interrogate (or at least display) the resulting list.

I'd like to be able to pull items off the returned IO [(Integer, Integer)] but I'm not entirely sure how to proceed. I understand that I can't simply convert it to a vanilla list (this is covered sufficiently elsewhere) so presumably I either need to:

• extend the IO (monad?) somehow
• write a custom list of tuples shuffler
• use some other method I haven't learnt yet

Anecdotally, I believe this can be done "uncleanly" but I don't want to go to programmer hell until I understand how hot the fires are...

Any idea how best to proceed?

• BTW, `do {xs <- myAction; print xs}` is better written as `myAction >>= print`.
– user39685
Commented Apr 9, 2014 at 12:24
• OK, thanks. I wasn't really sure of what I was doing beyond deck=shuffle cards Commented Apr 9, 2014 at 12:47

In abstract terms, what you should do is push the `IO` part as "high" up in your code as possible, so that as little code as possible knows about IO.

In more concrete terms, for your problem, `shuffle` and `myAction` don't need to know about IO, and also don't need to know how the randomness is generated. They just need the randomness passed in as a parameter. So what you can do is, generate the random value in `main`, and then pass it in as a pure value to `myAction` and/or `shuffle`.

You should end up with types like `shuffle :: randomness -> [a] -> [a]` and `myAction :: randomness -> [a]`, where "randomness" is generated in `main`. Now your return values aren't polluted with `IO`, and it's easy to work with them.*

AFAIK, this pattern -- where you split your code into "pure" and "impure" portions (and hope that most of it is "pure" :) ) -- is pretty common in Haskell.

*: if you're ever stuck in `IO`, read up on functors (`fmap`), applicatives (`liftA2`, `<*>`, etc.), monads (`liftM`, `>>=`, etc.), and lifting. It's still a pain, but using those you can work on the `a` part of `IO a`.

• OK, maybe if I just write something that takes a list and swaps two values I can call this repeatedly rather than use IO. Or at least until I've learnt a little more Haskell. Commented Apr 9, 2014 at 12:52
• @RobbieDee yeah, make sure that your `shuffle` function is pure. Then it's easy to test and to play with in ghci. You can always use pure stuff from evil code, but you (generally) can't do something evil without becoming evil yourself! (evil = using IO, pure = not using IO)
– user39685
Commented Apr 9, 2014 at 13:04
• Wow, this whole pure vs impure thing is kicking my butt. You can't seem to do anything pure with random since it isn't (or shouldn't be) repeatable. I can't even seem to pass the random data into the program as that then becomes impure. For now I've got another imperative program generating random numbers list which I then drop into the source code. Not perfect, but it'll have to do me for now. Commented Apr 10, 2014 at 12:06
• @RobbieDee the place where you generate the random value is impure (since presumably you want it to be actually random, which means it'll depend on some outside state), but where you use it is pure. So in your `main` function, generate a random value. But then pass it as a simple parameter wherever you want to use it.
– user39685
Commented Apr 10, 2014 at 13:02
• Ah, OK. I was thinking anything in main had to go through the IO monad but you're right, I can just do: main = print \$ cardTrick [My 52 random ints]. Thanks man! :) Commented Apr 15, 2014 at 12:36