on aaa775b help sign in
171 lines 12 kB history raw
1------------------------------------------------------------------------------
2-- CPP macros for common instances
3------------------------------------------------------------------------------
5-- XXX use template haskell instead and include Monoid and IsStream instances
6-- as well.
8#define MONADPARALLEL , MonadAsync m
10#define MONAD_COMMON_INSTANCES(STREAM,CONSTRAINT) \
11instance Monad m => Functor (STREAM m) where { \
12 {-# INLINE fmap #-}; \
13 fmap f (STREAM m) = \
14 STREAM $ D.toStreamK $ D.mapM (return . f) $ D.fromStreamK m; \
15 {-# INLINE (<$) #-}; \
16 (<$) = fmap . const }; \
17 \
18instance (MonadBase b m, Monad m CONSTRAINT) => MonadBase b (STREAM m) where {\
19 liftBase = liftBaseDefault }; \
20 \
21instance (MonadIO m CONSTRAINT) => MonadIO (STREAM m) where { \
22 liftIO = lift . liftIO }; \
23 \
24instance (MonadThrow m CONSTRAINT) => MonadThrow (STREAM m) where { \
25 throwM = lift . throwM }; \
26 \
27{- \
28instance (MonadError e m CONSTRAINT) => MonadError e (STREAM m) where { \
29 throwError = lift . throwError; \
30 catchError m h = \
31 fromStream $ withCatchError (toStream m) (\e -> toStream $ h e) }; \
32-} \
33 \
34instance (MonadReader r m CONSTRAINT) => MonadReader r (STREAM m) where { \
35 ask = lift ask; \
36 local f (STREAM m) = STREAM $ K.withLocal f m }; \
37 \
38instance (MonadState s m CONSTRAINT) => MonadState s (STREAM m) where { \
39 {-# INLINE get #-}; \
40 get = lift get; \
41 {-# INLINE put #-}; \
42 put x = lift (put x); \
43 {-# INLINE state #-}; \
44 state k = lift (state k) }
46------------------------------------------------------------------------------
47-- Lists
48------------------------------------------------------------------------------
50-- Serial streams can act like regular lists using the Identity monad
52-- XXX Show instance is 10x slower compared to read, we can do much better.
53-- The list show instance itself is really slow.
55-- XXX The default definitions of "<" in the Ord instance etc. do not perform
56-- well, because they do not get inlined. Need to add INLINE in Ord class in
57-- base?
59#define NFDATA1_INSTANCE(STREAM) \
60instance NFData1 (STREAM Identity) where { \
61 {-# INLINE liftRnf #-}; \
62 liftRnf f (STREAM xs) = runIdentity $ P.foldl' (\_ x -> f x) () xs}
64#define LIST_INSTANCES(STREAM) \
65instance IsList (STREAM Identity a) where { \
66 type (Item (STREAM Identity a)) = a; \
67 {-# INLINE fromList #-}; \
68 fromList xs = STREAM $ P.fromList xs; \
69 {-# INLINE toList #-}; \
70 toList (STREAM xs) = runIdentity $ P.toList xs }; \
71 \
72instance Eq a => Eq (STREAM Identity a) where { \
73 {-# INLINE (==) #-}; \
74 (==) (STREAM xs) (STREAM ys) = runIdentity $ P.eqBy (==) xs ys }; \
75 \
76instance Ord a => Ord (STREAM Identity a) where { \
77 {-# INLINE compare #-}; \
78 compare (STREAM xs) (STREAM ys) = runIdentity $ P.cmpBy compare xs ys; \
79 {-# INLINE (<) #-}; \
80 x < y = case compare x y of { LT -> True; _ -> False }; \
81 {-# INLINE (<=) #-}; \
82 x <= y = case compare x y of { GT -> False; _ -> True }; \
83 {-# INLINE (>) #-}; \
84 x > y = case compare x y of { GT -> True; _ -> False }; \
85 {-# INLINE (>=) #-}; \
86 x >= y = case compare x y of { LT -> False; _ -> True }; \
87 {-# INLINE max #-}; \
88 max x y = if x <= y then y else x; \
89 {-# INLINE min #-}; \
90 min x y = if x <= y then x else y; }; \
91 \
92instance Show a => Show (STREAM Identity a) where { \
93 showsPrec p dl = showParen (p > 10) $ \
94 showString "fromList " . shows (toList dl) }; \
95 \
96instance Read a => Read (STREAM Identity a) where { \
97 readPrec = parens $ prec 10 $ do { \
98 Ident "fromList" <- lexP; \
99 fromList <$> readPrec }; \
100 readListPrec = readListPrecDefault }; \
101 \
102instance (a ~ Char) => IsString (STREAM Identity a) where { \
103 {-# INLINE fromString #-}; \
104 fromString xs = STREAM $ P.fromList xs }; \
105 \
106instance NFData a => NFData (STREAM Identity a) where { \
107 {-# INLINE rnf #-}; \
108 rnf (STREAM xs) = runIdentity $ P.foldl' (\_ x -> rnf x) () xs}; \
110-------------------------------------------------------------------------------
111-- Foldable
112-------------------------------------------------------------------------------
114-- The default Foldable instance has several issues:
115-- 1) several definitions do not have INLINE on them, so we provide
116-- re-implementations with INLINE pragmas.
117-- 2) the definitions of sum/product/maximum/minimum are inefficient as they
118-- use right folds, they cannot run in constant memory. We provide
119-- implementations using strict left folds here.
121#define FOLDABLE_INSTANCE(STREAM) \
122instance (Foldable m, Monad m) => Foldable (STREAM m) where { \
123 \
124 {-# INLINE foldMap #-}; \
125 foldMap f (STREAM xs) = fold $ P.foldr (mappend . f) mempty xs; \
126 \
127 {-# INLINE foldr #-}; \
128 foldr f z t = appEndo (foldMap (Endo #. f) t) z; \
129 \
130 {-# INLINE foldl' #-}; \
131 foldl' f z0 xs = foldr f' id xs z0 \
132 where {f' x k = oneShot $ \z -> k $! f z x}; \
133 \
134 {-# INLINE length #-}; \
135 length = foldl' (\n _ -> n + 1) 0; \
136 \
137 {-# INLINE elem #-}; \
138 elem = any . (==); \
139 \
140 {-# INLINE maximum #-}; \
141 maximum = \
142 fromMaybe (errorWithoutStackTrace $ "maximum: empty stream") \
143 . toMaybe \
144 . foldl' getMax Nothing' where { \
145 getMax Nothing' x = Just' x; \
146 getMax (Just' mx) x = Just' $! max mx x }; \
147 \
148 {-# INLINE minimum #-}; \
149 minimum = \
150 fromMaybe (errorWithoutStackTrace $ "minimum: empty stream") \
151 . toMaybe \
152 . foldl' getMin Nothing' where { \
153 getMin Nothing' x = Just' x; \
154 getMin (Just' mn) x = Just' $! min mn x }; \
155 \
156 {-# INLINE sum #-}; \
157 sum = foldl' (+) 0; \
158 \
159 {-# INLINE product #-}; \
160 product = foldl' (*) 1 }
162-------------------------------------------------------------------------------
163-- Traversable
164-------------------------------------------------------------------------------
166#define TRAVERSABLE_INSTANCE(STREAM) \
167instance Traversable (STREAM Identity) where { \
168 {-# INLINE traverse #-}; \
169 traverse f (STREAM xs) = \
170 fmap STREAM $ runIdentity $ P.foldr consA (pure mempty) xs \
171 where { consA x ys = liftA2 K.cons (f x) ys }}