neat trick: parallel show
John Meacham
john at repetae.net
Mon Nov 10 18:32:17 EST 2003
while working on a random project, I had opprotunity to write a 'parallel show'
which concurrently evaluates everything needed to show a structure and lets you
print succesivly refined versions as vaules are calculated and filled in. it is
nice because a value that takes a long time (or perhaps forever) to evaluate at
the front of your structure doesn't keep you from seeing what else is in it. I
must say it has been a very useful little bit of code so thought I might share
the concept and was curious if anyone else does things like this..
it works something like
foo = [Right "foo", Left undefined, undefined, Right "here"]
parShow (parPretty foo) >>= putStrLn
=> "(Right foo) (Left _|_) _|_ (Right here)"
and succesive calls to parShow will fill in the _|_ values as they get evaluated.
my attached implementation is rather weak (my real one is tied into a project
and does wierd things with ANSI escape codes to redraw the screen as things get
evaluated and handles exceptions differently) but the gist is the same.
would people be interesting in me( or someone else :) ) turning this
into a full fledged library? does one alreoady exist which does this? I
was thinking integrating it into a real pretty printing system would be
handy but might be too much work, if there were a way to reuse an
existing pretty printing library without change and somehow add this
capability then that would be cool. I couldn't think of a way to do it
since the final 'render' routine obviously needs to be in the IO monad
so the MVars can be checked again when rerendering..
John
--
---------------------------------------------------------------------------
John Meacham - California Institute of Technology, Alum. - john at foo.net
---------------------------------------------------------------------------
-------------- next part --------------
module Main(main) where
import Control.Concurrent
import Maybe
import Monad
import System.IO.Unsafe
import Control.Exception
infixr 5 </>
infixr 6 <>,<+>
data Doc = DocStr !String | DocPost !Doc !(MVar Doc) | DocCat !Doc !Doc
text s = DocStr s
a <> b = DocCat a b
a <+> b = a <> text " " <> b
a </> b = a <> text "\n" <> b
post els d = DocPost els $! unsafePerformIO $ do
mv <- newEmptyMVar
forkIO $ do
handle (\_ -> return ()) $ evaluate d >>= putMVar mv
return mv
postb d = post (text "_|_") d
parShow :: Doc -> IO String
parShow (DocStr s) = return s
parShow (DocCat a b) = do
na <- parShow a
nb <- parShow b
return (na ++ nb)
parShow (DocPost els mv) = do
md <- tryTakeMVar mv
parShow (fromMaybe els md)
parShowAll :: Doc -> String
parShowAll (DocStr s) = s
parShowAll (DocCat a b) = parShowAll a ++ parShowAll b
parShowAll (DocPost _ mv) = parShowAll (unsafePerformIO $ readMVar mv )
foo = [Right "foo", Left undefined, undefined, Right "here"]
foo2 = undefined
parPretty xs = postb (foldl (<+>) (text "") $ map (postb . parPrettyE) xs)
parPrettyE (Left l) = text "(Left" <+> postb (text l) <> text ")"
parPrettyE (Right r) = text "(Right" <+> postb (text r) <> text ")"
main = do
let foo_p = parPretty foo
let foo2_p = parPretty foo2
putStrLn "parShow foo_p"
parShow foo_p >>= putStrLn
putStrLn "parShow foo2_p"
parShow foo2_p >>= putStrLn
putStrLn "parShow foo_p"
parShow foo_p >>= putStrLn
--putStrLn "parShowAll foo"
--putStrLn $ parShowAll foo_p
More information about the Haskell
mailing list