3
I studied the topic of Monad and decided to make a program to test my knowledge.
import Control.Monad.IO.Class (liftIO)
import qualified Control.Monad.State as ST
import Control.Monad.Trans.State (StateT (..), evalStateT, get, put)
import qualified Control.Monad.Trans.Writer as WT
import Data.List (sort)
import Prelude hiding (max)
import System.Random
randomSt :: (RandomGen g, Random a, Num a) => a -> ST.State g a
randomSt max = ST.state $ randomR (1, max)
lottery :: Integer -> Integer-> StateT [Integer] IO [Integer]
lottery 0 _ = get >>= return
lottery n max = do
xs <- get
x <- liftIO $ randomRIO (1, max)
if x `elem` xs
then lottery n max
else do put (x:xs)
lottery (n - 1) max
lotteryWt :: Integer -> Integer -> WT.WriterT [String] (StateT [Integer] (ST.State StdGen)) [Integer]
lotteryWt 0 _ = ST.lift get >>= return
lotteryWt n max = do
xs <- ST.lift get
x <- ST.lift . ST.lift $ randomSt max
g <- ST.lift . ST.lift $ get
WT.tell [show x ++ " " ++ show n ++ ", state from StateT " ++ show xs ++ ", state from State " ++ show g]
if x `elem` xs
then lotteryWt n max
else do ST.lift $ put (x:xs)
lotteryWt (n - 1) max
main :: IO ()
main = do x <- evalStateT (lottery 6 60) []
g <- newStdGen
let y = ST.evalState (evalStateT (WT.runWriterT (lotteryWt 6 60)) []) g
putStrLn $ show $ sort x
putStrLn $ show $ sort (fst y)
mapM_ putStrLn (snd y)
I have two stacks of Monad’s one StateT [Integer] IO [Integer]
and the other WriterT ...
. For each Ottery function, I extract the values of each Monad.
I wanted to understand if this is the right way to use several Monad. It is a good practice this type of use?
I did some research on the subject Haskell - Avoiding lift with Monad Transformers and If you’re using lift, you’re Doing it wrongly (probably). But I didn’t find an answer, as soon as I find something, I’ll post.
– lemoce