Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Haskell help, /prog/!

Name: Anonymous 2008-09-16 15:04


-- create a random tree.
randomTree :: Random r => IO (BinaryTree r)
randomTree =
     -- randomly pick the left and right sides.
  do leftIO  <- pick(randomLeaf, randomBranch)
     rightIO <- pick(randomLeaf, randomBranch)
     -- "un-IO" the sides.
     left    <- leftIO
     right   <- rightIO
     -- get a random value for the top of the branch/tree.
     value   <- randomIO
     -- create branch and return.
     return (Branch left value right)
  where
    -- return left or right at random.
    pick (left, right) =
      do useLeft <- randomRIO(True, False)
         if useLeft then return left else return right
    -- create a random leaf.
    randomLeaf =
      do value <- randomIO
         let leaf = Leaf value
         return leaf
    -- setup an alias.
    randomBranch = randomTree


This code actually works fine, but I'm wondering if there's a way to simplify the "leftIO/rightIO" stuff. Is there some sort of "double arrow" that will un-Monad twice, or is this verbosity unavoidable?

Name: Anonymous 2008-09-21 11:01

>>43,44
Despite the tree generation now being lazy, pruning a resulting tree still wouldn't guarantee termination upon printing. That's because each node's generation depends on state created by the generation of all nodes to its left. For pruning to do what's expected you have to split the random generator before each recursion in the tree generation.

import Control.Monad.State
import Control.Arrow
import System.Random
import System

data BinaryTree a = Empty
                  | Node a (BinaryTree a) (BinaryTree a)
           deriving Show

randomRS :: (RandomGen g, Random a) => (a, a) -> State g a
randomRS bounds = State $ randomR bounds

splitS :: RandomGen g => State g a -> State g a
splitS fork = State $ first (evalState fork) . split

randomTreeS :: (RandomGen g, Random a, Eq a) => (a, a) -> State g (BinaryTree a)
randomTreeS bounds@(l, r)
   | l == r = return Empty
   | otherwise = do v <- randomRS bounds
                    splitS $ liftM2 (Node v) (randomTreeS (l, v)) 
                                             (randomTreeS (v, r))

instance (Random a, Bounded a, Eq a) => Random (BinaryTree a) where
   randomR = error "randomR: (BinaryTree a) does not implement this method"
   random = runState $ randomTreeS (minBound, maxBound)

prune :: Integral i => i -> BinaryTree a -> BinaryTree a
prune 0 _ = Empty
prune height tree
   | height < 0 = error "prune: height must be non-negative"
   | otherwise =
        case tree of Node v l r -> Node v (ascend l) (ascend r)
                     Empty      -> Empty
   where ascend = prune (height - 1)

main :: IO ()
main = print =<< liftM2 prune (fmap (read . head) getArgs)
                              (randomIO :: IO (BinaryTree Int))

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List