This repository has been archived by the owner on Jun 13, 2023. It is now read-only.
forked from simonmar/parconc-examples
-
Notifications
You must be signed in to change notification settings - Fork 2
/
findpar5.hs
90 lines (73 loc) · 2.39 KB
/
findpar5.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{-# 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
-- <<find
find :: String -> 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>
-- >>
-- <<subfind
subfind :: String -> 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