Paul Moore wrote:

... 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's really not true. getContents looks simple from the outside, and it *can* be simple underneath, too.

You can write a getContents on an arbitrary source of data with just one built-in action and two other primitives. The built-in is unsafeInterleaveIO, and the primitives from your data source are "get me the next item" and "am I done yet?".

getContents :: MyDataItem a => DataSource a -> IO [a]

getContents myDataSource = unsafeInterleaveIO $ do
  empty <- amIDoneYet myDataSource
  if empty
    then return []
    else do x <- getMeTheNextItem myDataSource
            xs <- getContents myDataSource
            return (x:xs)

If you're providing this in a library, you have to consider what you should do for your consumer if amIDoneYet or getMeTheNextItem does "the wrong thing", but that's hardly unusual.

You can make the implementation complex, so that it prefetches data, handles exceptions, and whatnot, but the basic idea isn't too terribly scary. You'll see this pattern in a number of Haskell libraries (System.IO, Data.ByteString.Lazy, Control.Concurrent.Chan, and more).

        <b
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to