module Control.Monad.Par.AList
(
AList(..),
empty, singleton, cons, head, tail, length, null, append,
toList, fromList, fromListBalanced,
filter, map, partition,
parBuildThresh, parBuildThreshM,
parBuild, parBuildM,
depth, balance
)
where
import Control.DeepSeq
import Prelude hiding (length,head,tail,null,map,filter)
import qualified Prelude as P
import qualified Data.List as L
import qualified Control.Monad.Par.Combinator as C
import Control.Monad.Par.Class
import Data.Typeable
import qualified Data.Serialize as S
data AList a = ANil | ASing a | Append (AList a) (AList a) | AList [a]
deriving (Typeable)
instance NFData a => NFData (AList a) where
rnf ANil = ()
rnf (ASing a) = rnf a
rnf (Append l r) = rnf l `seq` rnf r
rnf (AList l) = rnf l
instance Show a => Show (AList a) where
show al = "fromList "++ show (toList al)
instance S.Serialize a => S.Serialize (AList a) where
put al = S.put (toList al)
get = do x <- S.get
return (fromList x)
append :: AList a -> AList a -> AList a
append ANil r = r
append l ANil = l
append l r = Append l r
empty :: AList a
empty = ANil
singleton :: a -> AList a
singleton = ASing
fromList :: [a] -> AList a
fromList = AList
fromListBalanced :: [a] -> AList a
fromListBalanced xs = go xs (P.length xs)
where
go _ 0 = ANil
go ls 1 = case ls of
(h:_) -> ASing h
[] -> error "the impossible happened"
go ls n =
let (q,r) = quotRem n 2 in
Append (go ls q)
(go (drop q ls) (q+r))
balance :: AList a -> AList a
balance = fromListBalanced . toList
cons :: a -> AList a -> AList a
cons x ANil = ASing x
cons x al = Append (ASing x) al
head :: AList a -> a
head al =
case loop al of
Just x -> x
Nothing -> error "cannot take head of an empty AList"
where
loop al =
case al of
Append l r -> case loop l of
x@(Just _) -> x
Nothing -> loop r
ASing x -> Just x
AList (h:_) -> Just h
AList [] -> Nothing
ANil -> Nothing
tail :: AList a -> AList a
tail al =
case loop al of
Just x -> x
Nothing -> error "cannot take tail of an empty AList"
where
loop al =
case al of
Append l r -> case loop l of
(Just x) -> Just (Append x r)
Nothing -> loop r
ASing _ -> Just ANil
AList (_:t) -> Just (AList t)
AList [] -> Nothing
ANil -> Nothing
length :: AList a -> Int
length ANil = 0
length (ASing _) = 1
length (Append l r) = length l + length r
length (AList l) = P.length l
null :: AList a -> Bool
null = (==0) . length
toList :: AList a -> [a]
toList a = go a []
where go ANil rest = rest
go (ASing a) rest = a : rest
go (Append l r) rest = go l $! go r rest
go (AList xs) rest = xs ++ rest
partition :: (a -> Bool) -> AList a -> (AList a, AList a)
partition p a = go a (ANil, ANil)
where go ANil acc = acc
go (ASing a) (ys, ns) | p a = (a `cons` ys, ns)
go (ASing a) (ys, ns) | otherwise = (ys, a `cons` ns)
go (Append l r) acc = go l $! go r acc
go (AList xs) (ys, ns) = (AList ys' `append` ys, AList ns' `append` ns)
where
(ys', ns') = L.partition p xs
depth :: AList a -> Int
depth ANil = 0
depth (ASing _) = 1
depth (AList _) = 1
depth (Append l r) = 1 + max (depth l) (depth r)
filter :: (a -> Bool) -> AList a -> AList a
filter p l = loop l
where
loop ANil = ANil
loop o@(ASing x) = if p x then o else ANil
loop (AList ls) = AList$ P.filter p ls
loop (Append x y) =
let l = loop x
r = loop y in
case (l,r) of
(ANil,ANil) -> ANil
(ANil,y) -> y
(x,ANil) -> x
(x,y) -> Append x y
map :: (a -> b) -> AList a -> AList b
map _ ANil = ANil
map f (ASing x) = ASing (f x)
map f (AList l) = AList (P.map f l)
map f (Append x y) = Append (map f x) (map f y)
parBuildThresh :: (NFData a, ParFuture f p) => Int -> C.InclusiveRange -> (Int -> a) -> p (AList a)
parBuildThresh threshold range fn =
C.parMapReduceRangeThresh threshold range
(return . singleton . fn) appendM empty
parBuildThreshM :: (NFData a, ParFuture f p) => Int -> C.InclusiveRange -> (Int -> p a) -> p (AList a)
parBuildThreshM threshold range fn =
C.parMapReduceRangeThresh threshold range
(\x -> fn x >>= return . singleton) appendM empty
parBuild :: (NFData a, ParFuture f p) => C.InclusiveRange -> (Int -> a) -> p (AList a)
parBuild range fn =
C.parMapReduceRange range (return . singleton . fn) appendM empty
parBuildM :: (NFData a, ParFuture f p) => C.InclusiveRange -> (Int -> p a) -> p (AList a)
parBuildM range fn =
C.parMapReduceRange range (\x -> fn x >>= return . singleton) appendM empty
instance Eq a => Eq (AList a) where
a == b = toList a == toList b
appendM :: ParFuture f p => AList a -> AList a -> p (AList a)
appendM x y = return (append x y)