
On Fri, Mar 02, 2007 at 02:58:21PM +0000, Paul Moore wrote:
On 02/03/07, Bayley, Alistair
wrote: There's a big difference between getContents and Takusen: getContents has a non-trivial implementation (using unsafeInterleaveIO) that allows it to return data lazily. Takusen has no such implementation.
... ie, there's deep dark magic involved in the seemingly simple getContents, which isn't easily available to mere mortals (or even semi-immortal library designers). That figures. It's a shame, but not totally unsurprising.
I think I understand it ... here a some illustrative (I hope!) examples: stefan@stefans:~$ ghci ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.7.20070223, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base ... linking ... done. Prelude> :m + System.IO. System.IO.Error System.IO.Unsafe Prelude> :m + System.IO.Unsafe Prelude System.IO.Unsafe> foo <- unsafeInterleaveIO (putStr "foo") -- note that IO does NOT happen immediately Prelude System.IO.Unsafe> show foo -- but forcing it causes the IO to happen (unsafely interleaved with printing (pun intentional)) "foo()" Prelude System.IO.Unsafe> show foo -- but now that it is in WHNF, forcing it again has no effect (laziness) "()" Prelude System.IO.Unsafe> -- a more interesting case is using unsafeInterleaveIO in list recursion Prelude System.IO.Unsafe> let myGetContents = unsafeInterleaveIO $ do { ch <- getChar; chs <- myGetContents ; return (ch:chs) } Prelude System.IO.Unsafe> -- simplified by omitting support for EOF handling and block reads Prelude System.IO.Unsafe> print . map reverse . lines =<< myGetContents f["oo? ?oof"Interrupted. Prelude System.IO.Unsafe> mapM_ putStrLn . map reverse . lines =<< myGetContents foo? ?oof bar! !rab muahahaha. .ahahahaum ^D^? Interrupted. Prelude System.IO.Unsafe>
That's what my earlier code looked like, and I found it harder to understand than the getContents/process/put approach. I'm trying to explore ways of factoring data manipulation code out of database access functions, but maybe that's not the right way of doing it.
I don't think it's possible to pursue this style of programming with Takusen. If you do, you'll have to process the entire result-set into a data structure and then process it, which has obvious memory implications.
Oh, well. It's mostly irrelevant for me anyway, as the data sets I'm actually playing with are small enough that slurping them into memory isn't an issue - so I just choose between a simple and decoupled implementation or a more complex and scalable one, which is a fairly standard optimisation choice.
Thanks for clarifying. Paul. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
HTH Stefan