dimanche 18 octobre 2020

How to create a tree of random values in Haskell?

I've been working on learning about the state monad. I'm working with trees, defined as follows... data Tree a = Unary (Tree a) | Binary (Tree a) (Tree a)| Ternary (Tree a) (Tree a) (Tree a) | Leaf a

What I'm currently trying to do is make a function with type signature randomize :: Tree a -> Tree Int that returns a tree where each leaf (Leaf a) is replaced by a leaf (Leaf 0) or a (Leaf 1) with equal probability.

I previously wrote a function I called label :: Enum b => Tree a -> b -> Tree b that traverses a Tree and replaces every Leaf a with a Leaf b where b is incremented every time a leaf is visited. It is defined as follows

label:: Enum b => Tree a -> b -> Tree b
label tree b = evalState (mapSucc (\s -> (s, succ s)) tree) b where 
    mapSucc f (Leaf a) = Leaf <$> state f
    mapSucc f (Unary t1) = Unary <$> mapSucc f t1
    mapSucc f (Binary t1 t2) = Binary <$> mapSucc f t1 <*> mapSucc f t2
    mapSucc f (Ternary t1 t2 t3) = Ternary <$> mapSucc f t1 <*> mapSucc f t2 <*> mapSucc f t3

These seem to be very similar problems, you are weaving the state through each, you're just producing values differently. I tried...

randomize tree = evalState ( mapRandom (randomR (0,1)) tree) newStdGen  where 
    mapRandom f (Leaf a) = Leaf <$> state f
    mapRandom f (Unary t1) = Unary <$> mapRandom f t1
    mapRandom f (Binary t1 t2) = Binary <$> mapRandom f t1 <*> mapRandom f t2
    mapRandom f (Ternary t1 t2 t3) = Ternary <$> mapRandom f t1 <*> mapRandom f t2 <*> mapRandom f t3

however the compiler gave me the following

state.hs:55:41: error:
    • No instance for (RandomGen (IO StdGen))
        arising from a use of ‘randomR’
    • In the first argument of ‘mapRandom’, namely ‘(randomR (0, 1))’
      In the first argument of ‘evalState’, namely
        ‘(mapRandom (randomR (0, 1)) tree)’
      In the expression:
        evalState (mapRandom (randomR (0, 1)) tree) newStdGen

I thought Int was an instance of random, so I'm not really sure what to do to get an instance of Random, and if I did manage that if my thought process is on the right path. Would my solution work if I were to get an instance of random. I guess I'm not sure if my shortcoming stems from simply not knowing how to use System.Random or if I am not understanding the type of function I need. I've spent a significant amount of time trying to make randomize work but to no avail. Any help with understanding would be greatly appreciated.




Aucun commentaire:

Enregistrer un commentaire