Yesterday morning I decided to stop procrastinating and start learning me some Haskell.
So far I've made this, which is a simple cli 'dice rolling' utility that can be used like:
$ ./dice 3d20
You rolled: 17
The code looks like this:
import Data.List.Split
import Data.Char
import Control.Monad
import Control.Monad.Random
import System.Environment
type Dice = (Int, Int)
diceCode :: String -> Dice
diceCode die = (parts!!0, parts!!1)
where
parts = [read x :: Int | x <- take 2 (splitOn "D" (map toUpper die))]
rollDie :: (RandomGen g) => Int -> Rand g Int
rollDie sides = getRandomR (1, sides)
rollDice :: (RandomGen g) => Dice -> Rand g Int
rollDice dice = liftM sum (sequence(replicate rolls (rollDie sides)))
where
rolls = fst dice
sides = snd dice
main = do
args <- getArgs
roll <- evalRandIO (rollDice (diceCode (args!!0)))
putStrLn ("You rolled: " ++ show roll)
I was able to get the diceCode 'parsing' function by myself without too much trouble.
The rollDie function is almost straight from an example in the Control.Monad.Random docs, which helped a lot.
I struggled for quite a while to find a recipe for summing the rolls in rollDice... it seemed to me I ought to use msum but I couldn't find a way to make it work. liftM sum seems to do exactly what I wanted though.
I also found the use of tuples quite cumbersome. In Python I could just do:
rolls, sides = dice
but I seem to have to use the horribly-named fst and snd functions to access the members in Haskell (?)
I guess the next part of my adventure is to try and incorporate this into a larger program, eg a simple game. It seems like the monadically-wrapped random int values are going to force the rest of the code to be 'monad-aware' (i.e. lots of use of liftM) and I wonder if there is a way to avoid this?