[Haskell-cafe] Re[2]: Why Haskell?

SevenThunders mattcbro at earthlink.net
Wed Jul 26 02:16:40 EDT 2006



Bulat Ziganshin-2 wrote:
> 
> Hello Matthew,
> 
> Sunday, July 23, 2006, 10:35:41 AM, you wrote:
> 
>  >>     sequence $ [ reffill b s | s <- [0..(fi temits)-1], b <- [0..(fi
>> nc)-1]]
> 
>> Now thats interesting.  I can see that this function is more appropriate
>> since I do not need to retrieve data from the IO monad,
>> but what I don't understand is why it's actually faster.  I will give it
>> a try and test it on a large set to see if things change.
> 
> let's see at their (possible) definitions:
> 
> sequence [] = return []
> sequence (action:actions) = do x <- action
>                                xs <- sequence actions
>                                return (x:xs)
>                                
> sequence_ [] = return ()
> sequence_ (action:actions) = do action
>                                 sequence_ actions
> 
> sequence_ is TAIL-RECURSIVE function. moreover, when it's inlined, the
> result is what just all the action in list are sequentially performed
> without creating any intermediate data structures. so, using sequence_
> in above example is equivalent to implementing this cycle by hand.
> 
> but when you use sequence, result of each action is saved and list
> of all results is built. this list requires 12 bytes per element, so
> you got 600 mb of garbage and much slower execution
> 
> 
> 
> -- 
> Best regards,
>  Bulat                            mailto:Bulat.Ziganshin at gmail.com
> 
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> 
> 

Well lo and behold I also need decent performance when doing a lot of IO
actions that do not discard their arguments.  For example suppose I want to
generate a huge array of random numbers.  I certainly don't want to multiply
my memory requirements by the factor of 12 you mention.  It doesn't seem too
hard, however to devise tail recursive functions that fit the bill.  For
example suppose I define a function  that repeatedly applies an IO action
like this

repIO act llist = let
	repIO' iolact (act) (x0:xl) =
		do
			lact <- iolact
			z <- act x0
			repIO' (return (z:lact)) act xl
	repIO' iolact act [] = iolact
	nullio = return []
	in
		repIO' nullio (act) llist	


I can then create a list of random numbers in the IO monad like this
main = repIO (\x -> (randomIO :: IO Double)) [1..10] >>= print

Of course this one reverses the input list indices. There must be  library
functions that support a more space efficient way to do these kinds of
repetitive sequential IO actions.  Ultimately for this little application I
want to map the result to an array inside the IO monad.  It looks like I
have to create the list first.

Suppose however I pulled the random value out of the IO monad using
unsafePerformIO separately for each index.  Lazy evaluation would cause the
IO action to occur in an unspecified order.  But for the randomIO function I
don't really care what order it's called in.  Would this have any other
unforseen consequences?  Are there cases where the IO action would only be
partially evaluated, messing up the random number generator?
-- 
View this message in context: http://www.nabble.com/Why-Haskell--tf1986013.html#a5498263
Sent from the Haskell - Haskell-Cafe forum at Nabble.com.



More information about the Haskell-Cafe mailing list