{-# LANGUAGE GeneralizedNewtypeDeriving #-} import System.Directory import Control.Concurrent import System.FilePath import System.Environment import Data.List hiding (find) import GHC.Conc (getNumCapabilities) import Text.Printf import qualified Control.Monad.Par as P hiding (runParIO) import Control.Monad.Par.IO import Control.Monad.IO.Class import Control.Exception main = do [s,d] <- getArgs n <- getNumCapabilities runParIO (unE (find s d)) >>= print -- < FilePath -> EParIO (Maybe FilePath) find s d = do fs <- liftIO $ getDirectoryContents d let fs' = sort $ filter (`notElem` [".",".."]) fs if any (== s) fs' then return (Just (d s)) else do let ps = map (d ) fs' -- <1> foldr (subfind s) dowait ps [] -- <2> where dowait as = loop (reverse as) -- <3> loop [] = return Nothing loop (a:as) = do -- <4> r <- get a -- <5> case r of Nothing -> loop as -- <6> Just a -> return (Just a) -- <7> -- >> -- < FilePath -> ([EVar (Maybe FilePath)] -> EParIO (Maybe FilePath)) -> [EVar (Maybe FilePath)] -> EParIO (Maybe FilePath) subfind s p inner asyncs = do isdir <- liftIO $ doesDirectoryExist p if not isdir then inner asyncs else do r <- new liftPar $ P.fork (putResult (find s p) r) inner (r : asyncs) -- >> -- An exception-handling version of the ParIO monad. Exceptions from -- IO computations are caught in liftIO, and propagated in the EParIO -- monad. An EVar is like an IVar, but can also contain an exception, -- which is propagated by 'get'. Instead of 'put' we have -- 'putResult', which runs an EParIO and puts the result (or an -- exception) into an EVar. -- newtype EParIO a = E { unE :: ParIO (Either SomeException a) } instance Monad EParIO where return a = E (return (Right a)) E m >>= k = E $ do r <- m case r of Left e -> return (Left e) Right a -> unE (k a) instance MonadIO EParIO where liftIO io = E $ liftIO (try io) liftPar :: ParIO a -> EParIO a liftPar p = E $ p >>= return . Right type EVar a = IVar (Either SomeException a) new :: EParIO (EVar a) new = liftPar P.new get :: EVar a -> EParIO a get evar = E $ P.get evar putResult :: EParIO a -> EVar a -> ParIO () putResult (E e) var = do e >>= P.put_ var