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

Pages: 1-4041-

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-16 15:34

import Control.Monad

-- create a random tree.
randomTree :: Random r => IO (BinaryTree r)
randomTree =
     -- randomly pick the left and right sides.
  do [left, right] <- replicateM 2 $ liftM2 pick randomLeaf randomBranch
     -- 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 = ([left, right] !!) =<< randomRIO (0, 1)
    -- create a random leaf.
    randomLeaf = fmap Leaf randomIO
    -- setup an alias.
    randomBranch = randomTree

Name: Anonymous 2008-09-16 15:38

Uhh... replace the following line:
pick left right = ([left, right] !!) =<< randomRIO (0, 1)
with this one:
pick left right = fmap ([left, right] !!) $ randomRIO (0, 1)

This is all untested, by the way.

Name: Anonymous 2008-09-16 15:45

>>3
Yeah, none of this seems to work, but thanks for the ideas.

Name: Anonymous 2008-09-16 15:49

Now replace this:
liftM2 pick randomLeaf randomBranch
with this:
join $ liftM2 pick randomLeaf randomBranch

Name: Anonymous 2008-09-16 15:51

>>1
Not that I know of (although I'm just learning Haskell). You might be able to get away with something fishy though, I have no idea if it would actually parse (let alone work) --

(<--) = (<-).(<-)

If there's a real way to do it, please do post :)

Name: >>6 2008-09-16 15:53

Oh jeez, I need to refresh the window every once in awhile, I guess. And spend some more time reading the docs, lol.

Name: Anonymous 2008-09-16 16:19

I tested it now, and as it turned into an infinite recursion, I realized you should take the liftM2 out. Sorry about that.

Name: Anonymous 2008-09-16 17:04

>>6
Is it that difficult to type ghci in your shell and test?
Syntax can't be composed.  Not in Haskell.

Name: Anonymous 2008-09-16 17:39

Final form:

import Control.Monad
import System.Random

-- create a random tree.
randomTree :: Random r => IO (BinaryTree r)
randomTree =
   liftM3 Branch randomBranch randomIO randomBranch
   where
      randomBranch = ([fmap Leaf randomIO, randomTree] !!) =<< randomRIO (0, 1)

Name: Anonymous 2008-09-16 17:44

Just remove the returns from pick.

Name: Anonymous 2008-09-16 17:45

Oh, and there's always the function join

Name: Anonymous 2008-09-16 18:03

FUCK OFF

Name: Anonymous 2008-09-16 22:06

So... I'm never going to learn Haskell if 9/10 experts can't agree on how to write simple tree algorithms

Name: Anonymous 2008-09-16 22:34

>>14
see >>10

Name: Anonymous 2008-09-17 19:27

Not OP. I was considering to consider learning Haskell, but I was completely put off by this thread. I'm glad to see so many Anonymous trying to help, but if it takes several people and several iterations of Perl-like mess to write a simple tree algorithm, then I see the language is way too experimental, weird and unpractical. It's not without value — these curious abstractions and techniques are worth trying somewhere, and Haskell is the place. Once they prove good enough, more practical languages (where you actually get stuff done) like FIOC should steal them.

Name: Anonymous 2008-09-17 19:46

>>16
>but if it takes several people and several iterations of Perl-like mess to write a simple tree algorithm
>serveral iterations
It's called refactoring. There's really only three versions: OP, >>2 and >>10

>Perl-like mess
Excuse me? >>1 and >>10 don't look like Perl, though I admit they might scare off noobs. The final version is actually quite clean and nice.

>simple tree algorithm
It only looks simple because it's in Haskell. This "function" can generate random trees of integers, characters, bools, and even *other trees.* Further, if anyone defines a new type and makes it an instance of the Random class, this function could generate random trees of that type, too, with no code changes.

It also looks simple because it's recursive, which is not a problem in since Haskell compilers optimize recursion.

BinaryTree.hs

module BinaryTree where

import Control.Monad
import Random

data BinaryTree a = Leaf a
                  | Branch (BinaryTree a) a (BinaryTree a)
                  deriving (Eq, Show)

instance Random r => Random (BinaryTree r) where
  -- create a random tree. I should probably re-write this somehow in
  -- randomR/random, but that's hard, so let's go shopping.
  randomIO = liftM3 Branch randomBranch randomIO randomBranch
    where
      randomBranch = randomRIO (0, 1) >>= ([liftM Leaf randomIO, randomIO] !!)

-- return a list of the elements of a tree from bottom-left.
elements :: BinaryTree a -> [a]
elements (Leaf a) = [a]
elements (Branch l a r) = elements l ++ [a] ++ elements r

-- get the maximum height of a tree.
height :: Integral i => BinaryTree a -> i
height (Leaf _) = 1
height (Branch l a r) = 1 + max (height l) (height r)

-- map a function onto a tree to produce a new tree.
treeMap :: (a -> b) -> BinaryTree a -> BinaryTree b
treeMap f (Leaf a) = Leaf (f a)
treeMap f (Branch l a r) = Branch (treeMap f l) (f a) (treeMap f r)


Main.hs

module Main where

import BinaryTree
import Random

main = do tree <- randomIO :: IO (BinaryTree (BinaryTree Integer)
          putStrLn $ show tree
          putStrLn $ show $ height tree

Name: Anonymous 2008-09-17 20:12

>>17
You should add a maximum height to the three, otherwise the chance that randomIO will terminate is very small.

Name: Anonymous 2008-09-17 20:33

I've seen messy Perl code in my lifetime. This code written in Haskell looks strange and I think it looks messy. Therefore, Haskell code is Perl-like code.
Great logic there, Edsger

Name: Anonymous 2008-09-17 21:01

>>18
It is possible that randomIO will not terminate, but it is unlikely. Though, one time I ran it and it kept going and eating my RAM, then my swap. Maybe it'd be good to add a maximum height, though.

Name: Anonymous 2008-09-17 21:43

It only looks simple
It is simple. You can cut out the middle man (type system) and make the random tree procedure take a random element procedure, so pretty much any language with funargs can do it with less bullshit (and usually less monad junk).

Puzzle: all operations in BinaryTree.hs can be written, IMHO bettr, as tree folds/unfolds. Do it.

Name: Anonymous 2008-09-17 23:41

>>21
But the type system allows for uniformity in creating (in this case) random values through the Random class, which is simpler than having "randomInteger", "randomBool", "randomDouble", "randomFoo", etc.

By tree folds, do you mean that I should right a fold function to work on the trees?

Name: Anonymous 2008-09-18 8:29

>>20
In randomBranch you have 0.5 chance of terminating and 0.5 chanche of calling randomIO recursively. randomIO calls randomBranch two times so on average one branch will terminate and the other continue. So it will run forever.

Name: Anonymous 2008-09-18 9:31

>>23
Go back to /prob/

Name: Anonymous 2008-09-18 12:51

>>23
Have you actually run the program yet? It can terminate, because it's a psuedo-random generator.

Name: Anonymous 2008-09-18 13:04

>>25
It can, but it might not; the possibility that it won't makes it fairly broken.

Name: Anonymous 2008-09-18 13:04

... which is part of it, but the reason some people need to go back to probabilities and statistics is because they are caught in the gambler's fallacy that "random" means "average" or "fair".  Each flip of a coin has a 50% chance for that flip and has no relation to any previous flips.

Name: Anonymous 2008-09-18 13:19

>>27
I'm not saying >>23 isn't a complete idiot, I just wanted to make the point that even though it can terminate it's not necessarily a correct program. I think a slightly more sane implementation would wrap the tree generation somehow such that it gets produced on-demand, which would allow you to instantiate and traverse possibly infinite tree without raping the balls off your machine.

Name: Anonymous 2008-09-18 13:47

>>28
That's exactly what Haskell does, because it's non-strict (a.k.a lazy.)

Name: Anonymous 2008-09-18 14:13

HASKELL FUCK OFFFFFFFFFFF

Name: Anonymous 2008-09-18 14:41

WHY IS THIS SHIT USING IO INSIDE THE MOTHERFUCKING FUNCTIONS

Name: Anonymous 2008-09-18 15:07

>>31
BECAUSE randomIO REQUIRES USE OF THE IO MONAD, SHITHEAD.

Name: Anonymous 2008-09-18 15:12

>>32
FUCK YOU AND FUCK YOUR IO MONAD, YOU AREN"T SICP

Name: Anonymous 2008-09-18 15:41

>>25
It can terminate but the chance that that happens is very small. The problem is that each call to randomIO can call itself recursively two times. So it grows exponentially. If you have n branches the chance that all n branches terminate and thus the algorithm terminates is only 0.5n.

Name: Anonymous 2008-09-18 16:51

>>34
So... Is it common to have to argue a great deal about whether your Haskell programs terminate?

Name: Anonymous 2008-09-18 17:06

P(Terminate) = .5 + .5 * P(Terminate) * P(Terminate)
P(Terminate) = 1

Proof completed.

Name: Anonymous 2008-09-18 17:21

>>35
Welcome to algorithms.

Name: Anonymous 2008-09-18 18:00

So... Haskell users on /prog are very susceptible to obvious trolls?

Name: Anonymous 2008-09-18 18:42

We happen to like discussing computability in Haskell programs.

Name: Anonymous 2008-09-18 19:20

>>36
But what is the height of the tree?

Name: Anonymous 2008-09-18 20:08

>>40
7

Name: Anonymous 2008-09-18 21:25

But what is the length() of a piece of String?

Name: Anonymous 2008-09-18 21:27

>>29
Sorry to disapoint you, but in this particular case the tree generation isn't lazy, because it's tied to the IO monad.

Name: Anonymous 2008-09-19 1:11

>>43

instance Random r => Random (BinaryTree r) where
  randomR (a, b) g = let (useA, g1) = random g in
                     if useA then (a, g1) else (b, g1)

  random g = let (leaf, g1) = random g in
             if leaf
               then let (value, g2) = random g1 in
                    (Leaf value, g2)
               else let (left,  g2) = random g1 in
                    let (right, g3) = random g2 in
                    let (value, g4) = random g3 in
                    (Branch left value right, g4)


There, no monads now. randomR doesn't really work like it's supposed to, but at least now there's no warnings.

Name: Anonymous 2008-09-19 10:17

>>44
I like monads.

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

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

randomS :: (RandomGen s, Random a) => State s a
randomS = State random

randomRS :: (RandomGen s, Random a) => (a, a) -> State s a
randomRS = State . randomR

randomTree :: (RandomGen s, Random a) => State s (BinaryTree a)
randomTree = ([return Empty, randomNode] !!) =<< randomRS (0, 1)

randomNode :: (RandomGen s, Random a) => State s (BinaryTree a)
randomNode = liftM3 Node randomS randomTree randomTree

instance Random a => Random (BinaryTree a) where
   --random = runState randomTree
   random = runState randomNode

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 = print =<< liftM2 prune (fmap (read . head) getArgs)
                              (randomIO :: IO (BinaryTree Int))

Name: Anonymous 2008-09-19 10:25

One of these days I need to set aside a week or so, hike out into the mountains with a copy of the Haskell documentation and just spend the week in quiet meditation reading and completing the exercises until I have some comprehension of this strange and wonderful language.

Name: Anonymous 2008-09-19 10:40

>>46
The Sussman?

Name: Anonymous 2008-09-19 16:29

Name: Anonymous 2008-09-20 9:18

http;//ATS.com/ats

Name: Anonymous 2008-09-20 12:03

I don't feel that it's a big question, so I'll ask here instead of making a new thread;

I want to make a list of each possible result of multiplying two-digit numbers. I can do it like this:

foo = [x*y | x <- [10..99], y <- [10..99]]

but how would I do it using double map? I mean a trick like this:

foo = map (map (\x -> (\y -> y*x)) [10..99]) [10..99]

except a working one.

Name: Anonymous 2008-09-20 12:06

I meant

foo = [x*y | x <- [10..99], y <- [x..99]]

Name: Anonymous 2008-09-20 12:29

in ATS you could write

let foo = cproduct (ditto 10 99) (fn x => ditto x 99)

Name: Anonymous 2008-09-20 12:47

>>50
[code=haskell]
foo = concatMap (\x->map (x*) [10..99]) [10..99]
[/code]

or

[code=haskell]
foo = concatMap (flip map [10..99] . (*)) [10..99]
[/code]

>>51

[code=haskell]
foo = concatMap (\x->map (x*) [x..99]) [10..99]
[/code]

Name: Anonymous 2008-09-20 12:59

>>51
foo = [10..99] >>= \x -> map (x*) [x..99]

Name: Anonymous 2008-09-20 13:44

>>51
liftM2 (*) [10 .. 99] [10 .. 99]

Name: Anonymous 2008-09-20 13:49

Now you fib(10) problems.

Name: Anonymous 2008-09-20 13:56

>>55
nub $ liftM2 (*) [10 .. 99] [10 .. 99]

Name: Anonymous 2008-09-20 16:50

>>56
I think you mean ``(fib 10)'' problems.

Name: Anonymous 2008-09-20 20:48

>>58
Now you have... fuck this.

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))

Name: Anonymous 2008-09-21 12:38

>>58
Now you have used a faggot quotes

Name: Anonymous 2008-09-21 15:50

>>60 was actually meant to quote >>44,45

Name: Anonymous 2008-09-22 16:52

I can't believe that /prog/ is actually being helpful to someone.

Name: Anonymous 2008-09-22 21:33

>>63
I agree. We must put a stop to this immediately.

Name: Anonymous 2008-09-23 0:49

>>64
I didn't help >>1, and I don't know who of you or the Sussman did it, but let me tell you this much: anii will be haxed tonight.

Name: Anonymous 2010-11-27 10:21

Name: Anonymous 2010-12-17 1:19

Are you GAY?
Are you a NIGGER?
Are you a GAY NIGGER?

If you answered "Yes" to all of the above questions, then GNAA (GAY NIGGER ASSOCIATION OF AMERICA) might be exactly what you've been looking for!

Name: Anonymous 2010-12-17 1:37

This post brought to you by the Gay Nigger Association of America

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