Saturday, March 24, 2007

HSS: James vs. the IO monad

Link to the source in the sidebar.

Primarily added functions to deal out the cards into the game structure. At times it has been a real struggle to think in the FP style. I've written a lot of C in my day, so it is hard for me to give up imperative programming. Sometimes I just want a loop, but instead I'm trying to force myself to use things like recursion instead.

For instance, it took me a little while to understand why I had to do use liftM here:

new_spider_game :: IO ()
new_spider_game = do
sd <- return shuffled_deck
nsg <- liftM deal_spider_game sd
putStrLn $ show nsg

It is also taking me a while to wrap my brain around the idea that once stuff is in the IO monad, it can't escape again (become pure). At some level I've known this for a long time (shortly after reading about Haskell) but my "fingers" (who actually do the implementation) haven't quite accepted that yet.

At any rate, I'm also not sure why I need the 2nd pattern (with the empty list as the 4th argument) for chunk_it:

-- Break up the list into chunks, returning a list of lists
-- and the remainder, if any.
chunk_it :: Int -> Int -> [[a]] -> [a] -> ([[a]], [a])
chunk_it _ 0 collect ys = (collect, ys)
chunk_it _ _ collect [] = (collect, [])
chunk_it size (next_count + 1) collect ys =
chunk_it size next_count (nextchunk : collect) remainder
where
(nextchunk, remainder) = splitAt size ys

Theoretically, with the last call to chunk_it will be 0, and so it should end right there. However, I end up with an additional empty list at the head of the talon. Here's how it is called:

deal_spider_game deck =
Spider_Game tableau talon [] []
where
(tableau1, rem1) = chunk_it 7 4 [] deck
(tableau2, rem2) = chunk_it 6 6 [] rem1
tableau = map flip_last (tableau1 ++ tableau2)
(talon, _) = chunk_it 10 5 [] rem2

Oh well, I'll figure it out eventually. Next I need to figure out some clean way to mark the cards that should be face-down as they are being dealt.

Edit: Nevermind, there's the new version deal_spider_game with the last card flipped. Wasn't a big deal... if you've got the right perspective. Originally had modified chunk_it, but that wasn't elegant. Actually, I'm going to modify chunk_it, and get rid of the extra null list argument. Make that a helper function for the real chunk_it.

No comments: