on master help sign in
Merge pull request #69 from composewell/stream-type

Fix Monoid instance, remove MonadError and numeric instances

commit99afd314d8dac037c6cabafc5493cf0d811ee9ff authorHarendra Kumar <harendra.kumar@gmail.com> dateMon 23 Apr 2018, 13:44 (9 years ago) parente1325ad0810ad7
8 files changed+272−513
Changelog.md+4 benchmark/Main.hs+7−3 examples/loops.hs+5−4 src/Streamly/Core.hs+25−67 src/Streamly/Streams.hs+88−379 stack.yaml+2−2 streamly.cabal+3−3 test/Main.hs+138−55
Changelog.md+4
@@ -28,6 +28,10 @@
2828 Stream types may have to be changed or type combinators may have to be added
2929 or removed to adapt to this change.
3030* Change the type of `foldrM` to make it consistent with `foldrM` in base.
31+* Remove the MonadError instance as it was not working correctly for
32+ parallel compositions. Use MonadThrow instead for error propagation.
33+* Remove Num/Fractional/Floating instances as they are not very useful. Use
34+ `fmap` and `liftA2` instead.
3135
3236### Deprecations
3337* Deprecate and rename the following symbols:
benchmark/Main.hs+7−3
@@ -95,6 +95,10 @@ main = do
9595map :: Monad m => (a -> Int) -> a -> m Int
9696map f x = return $ f x
9797
98+guard' :: (A.IsStream t, Applicative (t m)) => Bool -> t m ()
99+guard' True = pure ()
100+guard' False = A.nil
101+
98102{-# INLINABLE filter #-}
99103filter :: (Monad m, Alternative m) => (a -> Bool) -> a -> m a
100104filter cond x = guard (not $ cond x) >> return x
@@ -102,12 +106,12 @@ filter cond x = guard (not $ cond x) >> return x
102106amap :: Monad (s IO) => (Int -> Int) -> Int -> s IO Int
103107amap = Main.map
104108
105−afilter :: (Alternative (s IO), Monad (s IO)) => (Int -> Bool) -> Int -> s IO Int
106−afilter = Main.filter
109+afilter :: (A.IsStream s, Monad (s IO)) => (Int -> Bool) -> Int -> s IO Int
110+afilter cond x = guard' (not $ cond x) >> return x
107111
108112{-# INLINE streamly_basic #-}
109113streamly_basic
110− :: (Alternative (t IO), Monad (t IO), A.IsStream t)
114+ :: (Monad (t IO), A.IsStream t)
111115 => (forall a. t IO a -> IO [a])
112116 -> (t IO Int -> t IO Int -> t IO Int)
113117 -> IO Int
examples/loops.hs+5−4
@@ -1,5 +1,6 @@
11import Streamly
22import System.IO (stdout, hSetBuffering, BufferMode(LineBuffering))
3+import Streamly.Prelude (nil)
34
45main = do
56 liftIO $ hSetBuffering stdout LineBuffering
@@ -49,7 +50,7 @@ main = do
4950 loopTail :: Int -> SerialT IO Int
5051 loopTail x = do
5152 liftIO $ putStrLn "LoopTail..."
52− return x <> (if x < 3 then loopTail (x + 1) else empty)
53+ return x <> (if x < 3 then loopTail (x + 1) else nil)
5354
5455 -- Loops and then generates a value. The consumer can run only after the
5556 -- loop has finished. An infinite generator will not let the consumer run
@@ -57,7 +58,7 @@ main = do
5758 loopHead :: Int -> SerialT IO Int
5859 loopHead x = do
5960 liftIO $ putStrLn "LoopHead..."
60− (if x < 3 then loopHead (x + 1) else empty) <> return x
61+ (if x < 3 then loopHead (x + 1) else nil) <> return x
6162
6263-------------------------------------------------------------------------------
6364-- Concurrent (multi-threaded) adaptive demand-based stream generator loops
@@ -71,12 +72,12 @@ main = do
7172 loopTailA :: Int -> SerialT IO Int
7273 loopTailA x = do
7374 liftIO $ putStrLn "LoopTailA..."
74− return x `coparallel` (if x < 3 then loopTailA (x + 1) else empty)
75+ return x `coparallel` (if x < 3 then loopTailA (x + 1) else nil)
7576
7677 loopHeadA :: Int -> SerialT IO Int
7778 loopHeadA x = do
7879 liftIO $ putStrLn "LoopHeadA..."
79− (if x < 3 then loopHeadA (x + 1) else empty) `coparallel` return x
80+ (if x < 3 then loopHeadA (x + 1) else nil) `coparallel` return x
8081
8182-------------------------------------------------------------------------------
8283-- Parallel (fairly scheduled, multi-threaded) stream generator loops
src/Streamly/Core.hs+25−67
@@ -39,6 +39,10 @@ module Streamly.Core
3939 -- * Alternative
4040 , alt
4141
42+ -- * Transformers
43+ , withLocal
44+ , withCatchError
45+
4246 -- * Concurrent Stream Vars (SVars)
4347 , SVar
4448 , SVarSched (..)
@@ -53,20 +57,17 @@ module Streamly.Core
5357 )
5458where
5559
56−import Control.Applicative (Alternative (..))
5760import Control.Concurrent (ThreadId, forkIO,
5861 myThreadId, threadDelay)
5962import Control.Concurrent.MVar (MVar, newEmptyMVar, tryTakeMVar,
6063 tryPutMVar, takeMVar)
6164import Control.Exception (SomeException (..))
6265import qualified Control.Exception.Lifted as EL
63−import Control.Monad (MonadPlus(..), mzero, when)
64−import Control.Monad.Base (MonadBase (..), liftBaseDefault)
66+import Control.Monad (when)
6567import Control.Monad.Catch (MonadThrow, throwM)
6668import Control.Monad.Error.Class (MonadError(..))
6769import Control.Monad.IO.Class (MonadIO(..))
6870import Control.Monad.Reader.Class (MonadReader(..))
69−import Control.Monad.State.Class (MonadState(..))
7071import Control.Monad.Trans.Class (MonadTrans (lift))
7172import Control.Monad.Trans.Control (MonadBaseControl, liftBaseWith)
7273import Data.Atomics (atomicModifyIORefCAS,
@@ -184,15 +185,6 @@ cons a r = Stream $ \_ _ _ yld -> yld a r
184185repeat :: a -> Stream m a
185186repeat a = let x = cons a x in x
186187
187−------------------------------------------------------------------------------
188−-- Composing streams
189−------------------------------------------------------------------------------
190−
191−-- Streams can be composed sequentially or in parallel; in product style
192−-- compositions (monadic bind multiplies streams in a ListT fashion) or in sum
193−-- style compositions like 'Semigroup', 'Monoid', 'Alternative' or variants of
194−-- these.
195−
196188------------------------------------------------------------------------------
197189-- Semigroup
198190------------------------------------------------------------------------------
@@ -582,25 +574,14 @@ parallel :: MonadParallel m => Stream m a -> Stream m a -> Stream m a
582574parallel = joinStreamVar2 (SVarStyle Disjunction FIFO)
583575
584576-------------------------------------------------------------------------------
585−-- Instances (only used for deriving newtype instances)
577+-- Functor instace is the same for all types
586578-------------------------------------------------------------------------------
587579
588−-- Stream type is not exposed, these instances are only for deriving instances
589−-- for the newtype wrappers based on Stream.
590−
591−-- Dummy Instances, defined to enable the definition of other instances that
592−-- require a Monad constraint. Must be defined by the newtypes.
593−
594580instance Monad m => Functor (Stream m) where
595− fmap = undefined
596−
597−instance Monad m => Applicative (Stream m) where
598− pure = undefined
599− (<*>) = undefined
600−
601−instance Monad m => Monad (Stream m) where
602− return = pure
603− (>>=) = undefined
581+ fmap f m = Stream $ \_ stp sng yld ->
582+ let single = sng . f
583+ yield a r = yld (f a) (fmap f r)
584+ in (runStream m) Nothing stp single yield
604585
605586------------------------------------------------------------------------------
606587-- Alternative & MonadPlus
@@ -611,50 +592,27 @@ alt m1 m2 = Stream $ \_ stp sng yld ->
611592 let stop = runStream m2 Nothing stp sng yld
612593 in runStream m1 Nothing stop sng yld
613594
614−instance MonadParallel m => Alternative (Stream m) where
615− empty = nil
616− (<|>) = alt
617−
618−instance MonadParallel m => MonadPlus (Stream m) where
619− mzero = nil
620− mplus = (<|>)
621−
622595-------------------------------------------------------------------------------
623−-- Transformer
596+-- Transformers
624597-------------------------------------------------------------------------------
625598
626599instance MonadTrans Stream where
627600 lift mx = Stream $ \_ _ single _ -> mx >>= single
628601
629−instance (MonadBase b m, Monad m) => MonadBase b (Stream m) where
630− liftBase = liftBaseDefault
631−
632−------------------------------------------------------------------------------
633−-- Standard transformer instances
634−------------------------------------------------------------------------------
635−
636−instance MonadIO m => MonadIO (Stream m) where
637− liftIO = lift . liftIO
638−
639−instance MonadThrow m => MonadThrow (Stream m) where
640− throwM = lift . throwM
641−
642−-- XXX handle and test cross thread state transfer
643−instance MonadError e m => MonadError e (Stream m) where
644− throwError = lift . throwError
645− catchError m h = Stream $ \svr stp sng yld ->
646− let handle r = r `catchError` \e -> (runStream (h e)) svr stp sng yld
647− yield a r = yld a (catchError r h)
648− in handle $ (runStream m) svr stp sng yield
649−
650−instance MonadReader r m => MonadReader r (Stream m) where
651− ask = lift ask
652− local f m = Stream $ \svr stp sng yld ->
602+withLocal :: MonadReader r m => (r -> r) -> Stream m a -> Stream m a
603+withLocal f m =
604+ Stream $ \svr stp sng yld ->
653605 let single = local f . sng
654− yield a r = local f $ yld a (local f r)
606+ yield a r = local f $ yld a (withLocal f r)
655607 in (runStream m) svr (local f stp) single yield
656608
657−instance MonadState s m => MonadState s (Stream m) where
658− get = lift get
659− put x = lift (put x)
660− state k = lift (state k)
609+-- XXX handle and test cross thread state transfer
610+withCatchError
611+ :: MonadError e m
612+ => Stream m a -> (e -> Stream m a) -> Stream m a
613+withCatchError m h =
614+ Stream $ \svr stp sng yld ->
615+ let run x = runStream x svr stp sng yield
616+ handle r = r `catchError` \e -> run $ h e
617+ yield a r = yld a (withCatchError r h)
618+ in handle $ run m
src/Streamly/Streams.hs+88−379
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE ConstraintKinds #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE FlexibleInstances #-}
@@ -102,15 +103,14 @@ module Streamly.Streams
102103 )
103104where
104105
105−import Control.Applicative (Alternative (..), liftA2)
106−import Control.Monad (MonadPlus(..), ap)
107−import Control.Monad.Base (MonadBase (..))
108−import Control.Monad.Catch (MonadThrow)
109−import Control.Monad.Error.Class (MonadError(..))
106+import Control.Monad (ap)
107+import Control.Monad.Base (MonadBase (..), liftBaseDefault)
108+import Control.Monad.Catch (MonadThrow, throwM)
109+-- import Control.Monad.Error.Class (MonadError(..))
110110import Control.Monad.IO.Class (MonadIO(..))
111111import Control.Monad.Reader.Class (MonadReader(..))
112112import Control.Monad.State.Class (MonadState(..))
113−import Control.Monad.Trans.Class (MonadTrans)
113+import Control.Monad.Trans.Class (MonadTrans (lift))
114114import Data.Semigroup (Semigroup(..))
115115import Prelude hiding (zipWith)
116116import Streamly.Core ( MonadParallel, Stream(Stream)
@@ -266,6 +266,46 @@ async m = do
266266 sv <- S.newStreamVar1 (SVarStyle Disjunction LIFO) (toStream m)
267267 return $ fromSVar sv
268268
269+------------------------------------------------------------------------------
270+-- CPP macros for common instances
271+------------------------------------------------------------------------------
272+
273+-- XXX use template haskell instead and include Monoid and IsStream instances
274+-- as well.
275+
276+#define MONADPARALLEL , MonadParallel m
277+
278+#define MONAD_APPLICATIVE_INSTANCE(STREAM,CONSTRAINT) \
279+instance (Monad m CONSTRAINT) => Applicative (STREAM m) where { \
280+ pure = STREAM . singleton; \
281+ (<*>) = ap }
282+
283+#define MONAD_COMMON_INSTANCES(STREAM,CONSTRAINT) \
284+instance (MonadBase b m, Monad m CONSTRAINT) => MonadBase b (STREAM m) where {\
285+ liftBase = liftBaseDefault }; \
286+ \
287+instance (MonadIO m CONSTRAINT) => MonadIO (STREAM m) where { \
288+ liftIO = lift . liftIO }; \
289+ \
290+instance (MonadThrow m CONSTRAINT) => MonadThrow (STREAM m) where { \
291+ throwM = lift . throwM }; \
292+ \
293+{- \
294+instance (MonadError e m CONSTRAINT) => MonadError e (STREAM m) where { \
295+ throwError = lift . throwError; \
296+ catchError m h = \
297+ fromStream $ S.withCatchError (toStream m) (\e -> toStream $ h e) }; \
298+-} \
299+ \
300+instance (MonadReader r m CONSTRAINT) => MonadReader r (STREAM m) where { \
301+ ask = lift ask; \
302+ local f m = fromStream $ S.withLocal f (toStream m) }; \
303+ \
304+instance (MonadState s m CONSTRAINT) => MonadState s (STREAM m) where { \
305+ get = lift get; \
306+ put x = lift (put x); \
307+ state k = lift (state k) }
308+
269309------------------------------------------------------------------------------
270310-- SerialT
271311------------------------------------------------------------------------------
@@ -321,14 +361,7 @@ async m = do
321361-- streams as it explores only one stream at a time.
322362--
323363newtype SerialT m a = SerialT {getSerialT :: Stream m a}
324− deriving (Semigroup, Monoid, MonadTrans, MonadIO, MonadThrow)
325−
326−deriving instance MonadParallel m => Alternative (SerialT m)
327−deriving instance MonadParallel m => MonadPlus (SerialT m)
328−deriving instance (MonadBase b m, Monad m) => MonadBase b (SerialT m)
329−deriving instance MonadError e m => MonadError e (SerialT m)
330−deriving instance MonadReader r m => MonadReader r (SerialT m)
331−deriving instance MonadState s m => MonadState s (SerialT m)
364+ deriving (Semigroup, Monoid, Functor, MonadTrans)
332365
333366instance IsStream SerialT where
334367 toStream = getSerialT
@@ -338,11 +371,6 @@ instance IsStream SerialT where
338371{-# Deprecated StreamT "Please use SerialT instead." #-}
339372type StreamT = SerialT
340373
341−-- XXX The Functor/Applicative/Num instances for all the types are exactly the
342−-- same, how can we reduce this boilerplate (use TH)? We cannot derive them
343−-- from a single base type because they depend on the Monad instance which is
344−-- different for each type.
345−
346374------------------------------------------------------------------------------
347375-- Semigroup
348376------------------------------------------------------------------------------
@@ -367,66 +395,11 @@ instance Monad m => Monad (SerialT m) where
367395 in m Nothing stp single yield
368396
369397------------------------------------------------------------------------------
370−-- Applicative
371−------------------------------------------------------------------------------
372−
373−instance Monad m => Applicative (SerialT m) where
374− pure = SerialT . singleton
375− (<*>) = ap
376−
377−------------------------------------------------------------------------------
378−-- Functor
379−------------------------------------------------------------------------------
380−
381−instance Monad m => Functor (SerialT m) where
382− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
383− let single = sng . f
384− yield a r = yld (f a) (toStream $ fmap f (SerialT r))
385− in (S.runStream (toStream m)) Nothing stp single yield
386−
387−------------------------------------------------------------------------------
388−-- Num
398+-- Other instances
389399------------------------------------------------------------------------------
390400
391−instance (Monad m, Num a) => Num (SerialT m a) where
392− fromInteger n = pure (fromInteger n)
393−
394− negate = fmap negate
395− abs = fmap abs
396− signum = fmap signum
397−
398− (+) = liftA2 (+)
399− (*) = liftA2 (*)
400− (-) = liftA2 (-)
401−
402−instance (Monad m, Fractional a) => Fractional (SerialT m a) where
403− fromRational n = pure (fromRational n)
404−
405− recip = fmap recip
406−
407− (/) = liftA2 (/)
408−
409−instance (Monad m, Floating a) => Floating (SerialT m a) where
410− pi = pure pi
411−
412− exp = fmap exp
413− sqrt = fmap sqrt
414− log = fmap log
415− sin = fmap sin
416− tan = fmap tan
417− cos = fmap cos
418− asin = fmap asin
419− atan = fmap atan
420− acos = fmap acos
421− sinh = fmap sinh
422− tanh = fmap tanh
423− cosh = fmap cosh
424− asinh = fmap asinh
425− atanh = fmap atanh
426− acosh = fmap acosh
427−
428− (**) = liftA2 (**)
429− logBase = liftA2 logBase
401+MONAD_APPLICATIVE_INSTANCE(SerialT,)
402+MONAD_COMMON_INSTANCES(SerialT,)
430403
431404------------------------------------------------------------------------------
432405-- CoserialT
@@ -463,14 +436,7 @@ instance (Monad m, Floating a) => Floating (SerialT m a) where
463436-- streams as it needs to retain state for each unfinished stream.
464437--
465438newtype CoserialT m a = CoserialT {getCoserialT :: Stream m a}
466− deriving (Monoid, MonadTrans, MonadIO, MonadThrow)
467−
468−deriving instance MonadParallel m => Alternative (CoserialT m)
469−deriving instance MonadParallel m => MonadPlus (CoserialT m)
470−deriving instance (MonadBase b m, Monad m) => MonadBase b (CoserialT m)
471−deriving instance MonadError e m => MonadError e (CoserialT m)
472−deriving instance MonadReader r m => MonadReader r (CoserialT m)
473−deriving instance MonadState s m => MonadState s (CoserialT m)
439+ deriving (Functor, MonadTrans)
474440
475441{-# DEPRECATED InterleavedT "Please use 'CoserialT' instead." #-}
476442type InterleavedT = CoserialT
@@ -500,6 +466,14 @@ infixr 5 <=>
500466(<=>) :: IsStream t => t m a -> t m a -> t m a
501467(<=>) = coserial
502468
469+------------------------------------------------------------------------------
470+-- Monoid
471+------------------------------------------------------------------------------
472+
473+instance Monoid (CoserialT m a) where
474+ mempty = nil
475+ mappend = (<>)
476+
503477------------------------------------------------------------------------------
504478-- Monad
505479------------------------------------------------------------------------------
@@ -513,66 +487,11 @@ instance Monad m => Monad (CoserialT m) where
513487 in m Nothing stp single yield
514488
515489------------------------------------------------------------------------------
516−-- Applicative
517−------------------------------------------------------------------------------
518−
519−instance Monad m => Applicative (CoserialT m) where
520− pure = CoserialT . singleton
521− (<*>) = ap
522−
523−------------------------------------------------------------------------------
524−-- Functor
525−------------------------------------------------------------------------------
526−
527−instance Monad m => Functor (CoserialT m) where
528− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
529− let single = sng . f
530− yield a r = yld (f a) (toStream $ fmap f (CoserialT r))
531− in (S.runStream (toStream m)) Nothing stp single yield
532−
533−------------------------------------------------------------------------------
534−-- Num
490+-- Other instances
535491------------------------------------------------------------------------------
536492
537−instance (Monad m, Num a) => Num (CoserialT m a) where
538− fromInteger n = pure (fromInteger n)
539−
540− negate = fmap negate
541− abs = fmap abs
542− signum = fmap signum
543−
544− (+) = liftA2 (+)
545− (*) = liftA2 (*)
546− (-) = liftA2 (-)
547−
548−instance (Monad m, Fractional a) => Fractional (CoserialT m a) where
549− fromRational n = pure (fromRational n)
550−
551− recip = fmap recip
552−
553− (/) = liftA2 (/)
554−
555−instance (Monad m, Floating a) => Floating (CoserialT m a) where
556− pi = pure pi
557−
558− exp = fmap exp
559− sqrt = fmap sqrt
560− log = fmap log
561− sin = fmap sin
562− tan = fmap tan
563− cos = fmap cos
564− asin = fmap asin
565− atan = fmap atan
566− acos = fmap acos
567− sinh = fmap sinh
568− tanh = fmap tanh
569− cosh = fmap cosh
570− asinh = fmap asinh
571− atanh = fmap atanh
572− acosh = fmap acosh
573−
574− (**) = liftA2 (**)
575− logBase = liftA2 logBase
493+MONAD_APPLICATIVE_INSTANCE(CoserialT,)
494+MONAD_COMMON_INSTANCES(CoserialT,)
576495
577496------------------------------------------------------------------------------
578497-- CoparallelT
@@ -618,17 +537,7 @@ instance (Monad m, Floating a) => Floating (CoserialT m a) where
618537-- as it explores only a bounded number of streams at a time.
619538--
620539newtype CoparallelT m a = CoparallelT {getCoparallelT :: Stream m a}
621− deriving (MonadTrans)
622−
623−deriving instance MonadParallel m => Monoid (CoparallelT m a)
624−deriving instance MonadParallel m => Alternative (CoparallelT m)
625−deriving instance MonadParallel m => MonadPlus (CoparallelT m)
626−deriving instance MonadParallel m => MonadIO (CoparallelT m)
627−deriving instance MonadParallel m => MonadThrow (CoparallelT m)
628−deriving instance (MonadBase b m, MonadParallel m) => MonadBase b (CoparallelT m)
629−deriving instance (MonadError e m, MonadParallel m) => MonadError e (CoparallelT m)
630−deriving instance (MonadReader r m, MonadParallel m) => MonadReader r (CoparallelT m)
631−deriving instance (MonadState s m, MonadParallel m) => MonadState s (CoparallelT m)
540+ deriving (Functor, MonadTrans)
632541
633542{-# DEPRECATED AsyncT "Please use 'CoparallelT' instead." #-}
634543type AsyncT = CoparallelT
@@ -657,6 +566,14 @@ instance MonadParallel m => Semigroup (CoparallelT m a) where
657566(<|) :: (IsStream t, MonadParallel m) => t m a -> t m a -> t m a
658567(<|) = coparallel
659568
569+------------------------------------------------------------------------------
570+-- Monoid
571+------------------------------------------------------------------------------
572+
573+instance MonadParallel m => Monoid (CoparallelT m a) where
574+ mempty = nil
575+ mappend = (<>)
576+
660577------------------------------------------------------------------------------
661578-- Monad
662579------------------------------------------------------------------------------
@@ -682,66 +599,11 @@ instance MonadParallel m => Monad (CoparallelT m) where
682599 where par = S.joinStreamVar2 (SVarStyle Conjunction LIFO)
683600
684601------------------------------------------------------------------------------
685−-- Applicative
602+-- Other instances
686603------------------------------------------------------------------------------
687604
688−instance MonadParallel m => Applicative (CoparallelT m) where
689− pure = CoparallelT . singleton
690− (<*>) = ap
691−
692−------------------------------------------------------------------------------
693−-- Functor
694−------------------------------------------------------------------------------
695−
696−instance Monad m => Functor (CoparallelT m) where
697− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
698− let single = sng . f
699− yield a r = yld (f a) (toStream $ fmap f (CoparallelT r))
700− in (S.runStream (toStream m)) Nothing stp single yield
701−
702−------------------------------------------------------------------------------
703−-- Num
704−------------------------------------------------------------------------------
705−
706−instance (MonadParallel m, Num a) => Num (CoparallelT m a) where
707− fromInteger n = pure (fromInteger n)
708−
709− negate = fmap negate
710− abs = fmap abs
711− signum = fmap signum
712−
713− (+) = liftA2 (+)
714− (*) = liftA2 (*)
715− (-) = liftA2 (-)
716−
717−instance (MonadParallel m, Fractional a) => Fractional (CoparallelT m a) where
718− fromRational n = pure (fromRational n)
719−
720− recip = fmap recip
721−
722− (/) = liftA2 (/)
723−
724−instance (MonadParallel m, Floating a) => Floating (CoparallelT m a) where
725− pi = pure pi
726−
727− exp = fmap exp
728− sqrt = fmap sqrt
729− log = fmap log
730− sin = fmap sin
731− tan = fmap tan
732− cos = fmap cos
733− asin = fmap asin
734− atan = fmap atan
735− acos = fmap acos
736− sinh = fmap sinh
737− tanh = fmap tanh
738− cosh = fmap cosh
739− asinh = fmap asinh
740− atanh = fmap atanh
741− acosh = fmap acosh
742−
743− (**) = liftA2 (**)
744− logBase = liftA2 logBase
605+MONAD_APPLICATIVE_INSTANCE(CoparallelT,MONADPARALLEL)
606+MONAD_COMMON_INSTANCES(CoparallelT, MONADPARALLEL)
745607
746608------------------------------------------------------------------------------
747609-- ParallelT
@@ -785,17 +647,7 @@ instance (MonadParallel m, Floating a) => Floating (CoparallelT m a) where
785647-- streams as it needs to retain state for each unfinished stream.
786648--
787649newtype ParallelT m a = ParallelT {getParallelT :: Stream m a}
788− deriving (MonadTrans)
789−
790−deriving instance MonadParallel m => Monoid (ParallelT m a)
791−deriving instance MonadParallel m => Alternative (ParallelT m)
792−deriving instance MonadParallel m => MonadPlus (ParallelT m)
793−deriving instance MonadParallel m => MonadIO (ParallelT m)
794−deriving instance MonadParallel m => MonadThrow (ParallelT m)
795−deriving instance (MonadBase b m, MonadParallel m) => MonadBase b (ParallelT m)
796−deriving instance (MonadError e m, MonadParallel m) => MonadError e (ParallelT m)
797−deriving instance (MonadReader r m, MonadParallel m) => MonadReader r (ParallelT m)
798−deriving instance (MonadState s m, MonadParallel m) => MonadState s (ParallelT m)
650+ deriving (Functor, MonadTrans)
799651
800652instance IsStream ParallelT where
801653 toStream = getParallelT
@@ -814,6 +666,14 @@ parallel m1 m2 = fromStream $ S.parallel (toStream m1) (toStream m2)
814666instance MonadParallel m => Semigroup (ParallelT m a) where
815667 (<>) = parallel
816668
669+------------------------------------------------------------------------------
670+-- Monoid
671+------------------------------------------------------------------------------
672+
673+instance MonadParallel m => Monoid (ParallelT m a) where
674+ mempty = nil
675+ mappend = (<>)
676+
817677------------------------------------------------------------------------------
818678-- Monad
819679------------------------------------------------------------------------------
@@ -824,66 +684,11 @@ instance MonadParallel m => Monad (ParallelT m) where
824684 where par = S.joinStreamVar2 (SVarStyle Conjunction FIFO)
825685
826686------------------------------------------------------------------------------
827−-- Applicative
828−------------------------------------------------------------------------------
829−
830−instance MonadParallel m => Applicative (ParallelT m) where
831− pure = ParallelT . singleton
832− (<*>) = ap
833−
834−------------------------------------------------------------------------------
835−-- Functor
687+-- Other instances
836688------------------------------------------------------------------------------
837689
838−instance Monad m => Functor (ParallelT m) where
839− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
840− let single = sng . f
841− yield a r = yld (f a) (toStream $ fmap f (ParallelT r))
842− in (S.runStream (toStream m)) Nothing stp single yield
843−
844−------------------------------------------------------------------------------
845−-- Num
846−------------------------------------------------------------------------------
847−
848−instance (MonadParallel m, Num a) => Num (ParallelT m a) where
849− fromInteger n = pure (fromInteger n)
850−
851− negate = fmap negate
852− abs = fmap abs
853− signum = fmap signum
854−
855− (+) = liftA2 (+)
856− (*) = liftA2 (*)
857− (-) = liftA2 (-)
858−
859−instance (MonadParallel m, Fractional a) => Fractional (ParallelT m a) where
860− fromRational n = pure (fromRational n)
861−
862− recip = fmap recip
863−
864− (/) = liftA2 (/)
865−
866−instance (MonadParallel m, Floating a) => Floating (ParallelT m a) where
867− pi = pure pi
868−
869− exp = fmap exp
870− sqrt = fmap sqrt
871− log = fmap log
872− sin = fmap sin
873− tan = fmap tan
874− cos = fmap cos
875− asin = fmap asin
876− atan = fmap atan
877− acos = fmap acos
878− sinh = fmap sinh
879− tanh = fmap tanh
880− cosh = fmap cosh
881− asinh = fmap asinh
882− atanh = fmap atanh
883− acosh = fmap acosh
884−
885− (**) = liftA2 (**)
886− logBase = liftA2 logBase
690+MONAD_APPLICATIVE_INSTANCE(ParallelT,MONADPARALLEL)
691+MONAD_COMMON_INSTANCES(ParallelT, MONADPARALLEL)
887692
888693------------------------------------------------------------------------------
889694-- Serially Zipping Streams
@@ -920,20 +725,12 @@ zipWith f m1 m2 = fromStream $ go (toStream m1) (toStream m2)
920725-- 'SerialT'.
921726--
922727newtype ZipSerial m a = ZipSerial {getZipSerial :: Stream m a}
923− deriving (Semigroup, Monoid)
728+ deriving (Functor, Semigroup, Monoid)
924729
925730{-# Deprecated ZipStream "Please use ZipSerial instead." #-}
926731-- | Same as ZipSerial.
927732type ZipStream = ZipSerial
928733
929−deriving instance MonadParallel m => Alternative (ZipSerial m)
930−
931−instance Monad m => Functor (ZipSerial m) where
932− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
933− let single = sng . f
934− yield a r = yld (f a) (toStream $ fmap f (ZipSerial r))
935− in (S.runStream (toStream m)) Nothing stp single yield
936−
937734instance Monad m => Applicative (ZipSerial m) where
938735 pure = ZipSerial . S.repeat
939736 (<*>) = zipWith id
@@ -942,46 +739,6 @@ instance IsStream ZipSerial where
942739 toStream = getZipSerial
943740 fromStream = ZipSerial
944741
945−instance (Monad m, Num a) => Num (ZipSerial m a) where
946− fromInteger n = pure (fromInteger n)
947−
948− negate = fmap negate
949− abs = fmap abs
950− signum = fmap signum
951−
952− (+) = liftA2 (+)
953− (*) = liftA2 (*)
954− (-) = liftA2 (-)
955−
956−instance (Monad m, Fractional a) => Fractional (ZipSerial m a) where
957− fromRational n = pure (fromRational n)
958−
959− recip = fmap recip
960−
961− (/) = liftA2 (/)
962−
963−instance (Monad m, Floating a) => Floating (ZipSerial m a) where
964− pi = pure pi
965−
966− exp = fmap exp
967− sqrt = fmap sqrt
968− log = fmap log
969− sin = fmap sin
970− tan = fmap tan
971− cos = fmap cos
972− asin = fmap asin
973− atan = fmap atan
974− acos = fmap acos
975− sinh = fmap sinh
976− tanh = fmap tanh
977− cosh = fmap cosh
978− asinh = fmap asinh
979− atanh = fmap atanh
980− acosh = fmap acosh
981−
982− (**) = liftA2 (**)
983− logBase = liftA2 logBase
984−
985742------------------------------------------------------------------------------
986743-- Parallely Zipping Streams
987744------------------------------------------------------------------------------
@@ -1017,19 +774,11 @@ zipAsyncWith = zipParallelWith
1017774-- 'SerialT'.
1018775--
1019776newtype ZipParallel m a = ZipParallel {getZipParallel :: Stream m a}
1020− deriving (Semigroup, Monoid)
777+ deriving (Functor, Semigroup, Monoid)
1021778
1022779{-# DEPRECATED ZipAsync "Please use ZipParallel instead." #-}
1023780type ZipAsync = ZipParallel
1024781
1025−deriving instance MonadParallel m => Alternative (ZipParallel m)
1026−
1027−instance Monad m => Functor (ZipParallel m) where
1028− fmap f m = fromStream $ Stream $ \_ stp sng yld ->
1029− let single = sng . f
1030− yield a r = yld (f a) (toStream $ fmap f (ZipParallel r))
1031− in (S.runStream (toStream m)) Nothing stp single yield
1032−
1033782instance MonadParallel m => Applicative (ZipParallel m) where
1034783 pure = ZipParallel . S.repeat
1035784 (<*>) = zipParallelWith id
@@ -1038,46 +787,6 @@ instance IsStream ZipParallel where
1038787 toStream = getZipParallel
1039788 fromStream = ZipParallel
1040789
1041−instance (MonadParallel m, Num a) => Num (ZipParallel m a) where
1042− fromInteger n = pure (fromInteger n)
1043−
1044− negate = fmap negate
1045− abs = fmap abs
1046− signum = fmap signum
1047−
1048− (+) = liftA2 (+)
1049− (*) = liftA2 (*)
1050− (-) = liftA2 (-)
1051−
1052−instance (MonadParallel m, Fractional a) => Fractional (ZipParallel m a) where
1053− fromRational n = pure (fromRational n)
1054−
1055− recip = fmap recip
1056−
1057− (/) = liftA2 (/)
1058−
1059−instance (MonadParallel m, Floating a) => Floating (ZipParallel m a) where
1060− pi = pure pi
1061−
1062− exp = fmap exp
1063− sqrt = fmap sqrt
1064− log = fmap log
1065− sin = fmap sin
1066− tan = fmap tan
1067− cos = fmap cos
1068− asin = fmap asin
1069− atan = fmap atan
1070− acos = fmap acos
1071− sinh = fmap sinh
1072− tanh = fmap tanh
1073− cosh = fmap cosh
1074− asinh = fmap asinh
1075− atanh = fmap atanh
1076− acosh = fmap acosh
1077−
1078− (**) = liftA2 (**)
1079− logBase = liftA2 logBase
1080−
1081790-------------------------------------------------------------------------------
1082791-- Type adapting combinators
1083792-------------------------------------------------------------------------------
stack.yaml+2−2
@@ -25,5 +25,5 @@ flags: {}
2525extra-package-dbs: []
2626rebuild-ghc-options: true
2727# For mac ports installed SDL library on Mac OS X
28−#extra-include-dirs:
29−#- /opt/local/include
28+extra-include-dirs:
29+- /opt/local/include
streamly.cabal+3−3
@@ -149,9 +149,9 @@ test-suite test
149149 , base >= 4.8 && < 5
150150 , hspec >= 2.0 && < 3
151151 , containers >= 0.5 && < 0.6
152− if impl(ghc < 8.0)
153− build-depends:
154− transformers >= 0.4 && < 0.6
152+ , transformers >= 0.4 && < 0.6
153+ , mtl >= 2.2 && < 3
154+ , exceptions >= 0.8 && < 0.11
155155 default-language: Haskell2010
156156
157157test-suite properties
test/Main.hs+138−55
@@ -5,6 +5,10 @@
55module Main (main) where
66
77import Control.Concurrent (threadDelay)
8+import Control.Exception (Exception, try)
9+import Control.Monad.Catch (throwM, MonadThrow)
10+import Control.Monad.Error.Class (throwError, MonadError)
11+import Control.Monad.Trans.Except (runExceptT, ExceptT)
812import Data.Foldable (forM_)
913import Data.List (sort)
1014import Test.Hspec
@@ -32,6 +36,7 @@ main :: IO ()
3236main = hspec $ do
3337 describe "Runners" $ do
3438 -- XXX move these to property tests
39+ -- XXX use an IORef to store and check the side effects
3540 it "simple serially" $
3641 (runStream . serially) (return (0 :: Int)) `shouldReturn` ()
3742 it "simple serially with IO" $
@@ -40,10 +45,10 @@ main = hspec $ do
4045 describe "Empty" $ do
4146 it "Monoid - mempty" $
4247 (toListSerial mempty) `shouldReturn` ([] :: [Int])
43− it "Alternative - empty" $
44− (toListSerial empty) `shouldReturn` ([] :: [Int])
45− it "MonadPlus - mzero" $
46− (toListSerial mzero) `shouldReturn` ([] :: [Int])
48+ -- it "Alternative - empty" $
49+ -- (toListSerial empty) `shouldReturn` ([] :: [Int])
50+ -- it "MonadPlus - mzero" $
51+ -- (toListSerial mzero) `shouldReturn` ([] :: [Int])
4752
4853 ---------------------------------------------------------------------------
4954 -- Functor
@@ -84,7 +89,26 @@ main = hspec $ do
8489 `shouldReturn` ([(1,2),(1,3)] :: [(Int, Int)])
8590
8691 ---------------------------------------------------------------------------
87− -- Monoidal Compositions
92+ -- Semigroup/Monoidal Composition strict ordering checks
93+ ---------------------------------------------------------------------------
94+
95+ -- test both (<>) and mappend to make sure we are using correct instance
96+ -- for Monoid that is using the right version of semigroup. Instance
97+ -- deriving can cause us to pick wrong instances sometimes.
98+
99+ describe "Serial interleaved (<>) ordering check" $ interleaveCheck coserially (<>)
100+ describe "Serial interleaved mappend ordering check" $ interleaveCheck coserially mappend
101+
102+ describe "Parallel interleaved (<>) ordering check" $ interleaveCheck parallely (<>)
103+ describe "Parallel interleaved mappend ordering check" $ interleaveCheck parallely mappend
104+
105+ describe "Coparallel (<>) time order check" $ parallelCheck coparallely (<>)
106+ describe "Coparallel mappend time order check" $ parallelCheck coparallely mappend
107+ describe "Parallel (<>) time order check" $ parallelCheck parallely (<>)
108+ describe "Parallel mappend time order check" $ parallelCheck parallely mappend
109+
110+ ---------------------------------------------------------------------------
111+ -- Monoidal Compositions, multiset equality checks
88112 ---------------------------------------------------------------------------
89113
90114 describe "Serial Composition" $ compose serially mempty id
@@ -94,14 +118,6 @@ main = hspec $ do
94118 describe "Semigroup Composition for ZipSerial" $ compose zipSerially mempty id
95119 describe "Semigroup Composition for ZipAsync" $ compose zipParallely mempty id
96120 -- XXX need to check alternative compositions as well
97− ---------------------------------------------------------------------------
98− -- Monoidal Composition ordering checks
99− ---------------------------------------------------------------------------
100−
101− describe "Serial interleaved ordering check" $ interleaveCheck coserially
102− describe "Parallel interleaved ordering check" $ interleaveCheck parallely
103− describe "Left biased parallel time order check" $ parallelCheck coparallely
104− describe "Fair parallel time order check" $ parallelCheck parallely
105121
106122 ---------------------------------------------------------------------------
107123 -- TBD Monoidal composition combinations
@@ -261,17 +277,108 @@ main = hspec $ do
261277 it "Nests two streams using applicative async composition" nestTwoAsyncApp
262278 it "Nests two streams using applicative parallel composition" nestTwoParallelApp
263279
264− it "Nests two streams using Num serial composition" nestTwoSerialNum
265− it "Nests two streams using Num interleaved composition" nestTwoInterleavedNum
266− it "Nests two streams using Num async composition" nestTwoAsyncNum
267− it "Nests two streams using Num parallel composition" nestTwoParallelNum
268−
269280 ---------------------------------------------------------------------------
270281 -- TBD Bind and Bind combinations
271282 ---------------------------------------------------------------------------
272283
273284 -- TBD combine all binds and all compose in one example
274285 describe "Miscellaneous combined examples" mixedOps
286+ describe "Simple MonadError and MonadThrow" simpleMonadError
287+
288+ {-
289+ describe "Composed MonadError serially" $ composeWithMonadError serially
290+ describe "Composed MonadError coserially" $ composeWithMonadError coserially
291+ describe "Composed MonadError coparallely" $ composeWithMonadError coparallely
292+ describe "Composed MonadError parallely" $ composeWithMonadError parallely
293+ -}
294+
295+ describe "Composed MonadThrow serially" $ composeWithMonadThrow serially
296+ describe "Composed MonadThrow coserially" $ composeWithMonadThrow coserially
297+ describe "Composed MonadThrow coparallely" $ composeWithMonadThrow coparallely
298+ describe "Composed MonadThrow parallely" $ composeWithMonadThrow parallely
299+
300+-- XXX need to test that we have promptly cleaned up everything after the error
301+-- XXX We can also check the output that we are expected to get before the
302+-- error occurs.
303+
304+data ExampleException = ExampleException String deriving (Eq, Show)
305+
306+instance Exception ExampleException
307+
308+simpleMonadError :: Spec
309+simpleMonadError = do
310+{-
311+ it "simple runExceptT" $ do
312+ (runExceptT $ runStream $ return ())
313+ `shouldReturn` (Right () :: Either String ())
314+ it "simple runExceptT with error" $ do
315+ (runExceptT $ runStream $ throwError "E") `shouldReturn` Left "E"
316+ -}
317+ it "simple try" $ do
318+ (try $ runStream $ return ())
319+ `shouldReturn` (Right () :: Either ExampleException ())
320+ it "simple try with throw error" $ do
321+ (try $ runStream $ throwM $ ExampleException "E")
322+ `shouldReturn` (Left (ExampleException "E") :: Either ExampleException ())
323+
324+composeWithMonadThrow
325+ :: ( IsStream t
326+ , Semigroup (t IO Int)
327+ , MonadThrow (t IO)
328+ )
329+ => (t IO Int -> SerialT IO Int) -> Spec
330+composeWithMonadThrow t = do
331+ it "Compose throwM, nil" $
332+ (try $ tl (throwM (ExampleException "E") <> A.nil))
333+ `shouldReturn` (Left (ExampleException "E") :: Either ExampleException [Int])
334+ it "Compose nil, throwM" $
335+ (try $ tl (A.nil <> throwM (ExampleException "E")))
336+ `shouldReturn` (Left (ExampleException "E") :: Either ExampleException [Int])
337+ oneLevelNestedSum "serially" serially
338+ oneLevelNestedSum "coserially" coserially
339+ oneLevelNestedSum "coparallely" coparallely
340+ oneLevelNestedSum "parallely" parallely
341+ -- XXX add two level nesting
342+
343+ oneLevelNestedProduct "serially" serially
344+ oneLevelNestedProduct "coserially" coserially
345+ oneLevelNestedProduct "coparallely" coparallely
346+ oneLevelNestedProduct "parallely" parallely
347+
348+ where
349+ tl = A.toList . t
350+ oneLevelNestedSum desc t1 =
351+ it ("One level nested sum " ++ desc) $ do
352+ let nested = (A.fromFoldable [1..10] <> throwM (ExampleException "E")
353+ <> A.fromFoldable [1..10])
354+ (try $ tl (A.nil <> t1 nested <> A.fromFoldable [1..10]))
355+ `shouldReturn` (Left (ExampleException "E") :: Either ExampleException [Int])
356+
357+ oneLevelNestedProduct desc t1 =
358+ it ("One level nested product" ++ desc) $ do
359+ let s1 = t $ foldMapWith (<>) return [1..4]
360+ s2 = t1 $ foldMapWith (<>) return [5..8]
361+ try $ tl (do
362+ x <- adapt s1
363+ y <- s2
364+ if (x + y > 10)
365+ then throwM (ExampleException "E")
366+ else return (x + y)
367+ )
368+ `shouldReturn` (Left (ExampleException "E") :: Either ExampleException [Int])
369+
370+_composeWithMonadError
371+ :: ( IsStream t
372+ , Semigroup (t (ExceptT String IO) Int)
373+ , MonadError String (t (ExceptT String IO))
374+ )
375+ => (t (ExceptT String IO) Int -> SerialT (ExceptT String IO) Int) -> Spec
376+_composeWithMonadError t = do
377+ let tl = A.toList . t
378+ it "Compose throwError, nil" $
379+ (runExceptT $ tl (throwError "E" <> A.nil)) `shouldReturn` Left "E"
380+ it "Compose nil, error" $
381+ (runExceptT $ tl (A.nil <> throwError "E")) `shouldReturn` Left "E"
275382
276383nestTwoSerial :: Expectation
277384nestTwoSerial =
@@ -290,13 +397,6 @@ nestTwoSerialApp =
290397 in toListSerial ((+) <$> s1 <*> s2)
291398 `shouldReturn` ([6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12] :: [Int])
292399
293−nestTwoSerialNum :: Expectation
294−nestTwoSerialNum =
295− let s1 = foldMapWith (<>) return [1..4]
296− s2 = foldMapWith (<>) return [5..8]
297− in toListSerial (s1 + s2)
298− `shouldReturn` ([6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12] :: [Int])
299−
300400nestTwoInterleaved :: Expectation
301401nestTwoInterleaved =
302402 let s1 = foldMapWith (<>) return [1..4]
@@ -314,13 +414,6 @@ nestTwoInterleavedApp =
314414 in toListInterleaved ((+) <$> s1 <*> s2)
315415 `shouldReturn` ([6,7,7,8,8,8,9,9,9,9,10,10,10,11,11,12] :: [Int])
316416
317−nestTwoInterleavedNum :: Expectation
318−nestTwoInterleavedNum =
319− let s1 = foldMapWith (<>) return [1..4]
320− s2 = foldMapWith (<>) return [5..8]
321− in toListInterleaved (s1 + s2)
322− `shouldReturn` ([6,7,7,8,8,8,9,9,9,9,10,10,10,11,11,12] :: [Int])
323−
324417nestTwoAsync :: Expectation
325418nestTwoAsync =
326419 let s1 = foldMapWith (<>) return [1..4]
@@ -339,13 +432,6 @@ nestTwoAsyncApp =
339432 in (toListAsync ((+) <$> s1 <*> s2) >>= return . sort)
340433 `shouldReturn` sort ([6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12] :: [Int])
341434
342−nestTwoAsyncNum :: Expectation
343−nestTwoAsyncNum =
344− let s1 = foldMapWith (<>) return [1..4]
345− s2 = foldMapWith (<>) return [5..8]
346− in (toListAsync (s1 + s2) >>= return . sort)
347− `shouldReturn` sort ([6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12] :: [Int])
348−
349435nestTwoParallel :: Expectation
350436nestTwoParallel =
351437 let s1 = foldMapWith (<>) return [1..4]
@@ -364,32 +450,29 @@ nestTwoParallelApp =
364450 in (toListParallel ((+) <$> s1 <*> s2) >>= return . sort)
365451 `shouldReturn` sort ([6,7,7,8,8,8,9,9,9,9,10,10,10,11,11,12] :: [Int])
366452
367−nestTwoParallelNum :: Expectation
368−nestTwoParallelNum =
369− let s1 = foldMapWith (<>) return [1..4]
370− s2 = foldMapWith (<>) return [5..8]
371− in (toListParallel (s1 + s2) >>= return . sort)
372− `shouldReturn` sort ([6,7,7,8,8,8,9,9,9,9,10,10,10,11,11,12] :: [Int])
373−
374453timed :: MonadIO (t IO) => Int -> t IO Int
375454timed x = liftIO (threadDelay (x * 100000)) >> return x
376455
377−interleaveCheck :: (IsStream t, Semigroup (t IO Int))
378− => (t IO Int -> SerialT IO Int) -> Spec
379−interleaveCheck t =
456+interleaveCheck :: IsStream t
457+ => (t IO Int -> SerialT IO Int)
458+ -> (t IO Int -> t IO Int -> t IO Int)
459+ -> Spec
460+interleaveCheck t f =
380461 it "Interleave four" $
381− (A.toList . t) ((singleton 0 <> singleton 1) <> (singleton 100 <> singleton 101))
462+ (A.toList . t) ((singleton 0 `f` singleton 1) `f` (singleton 100 `f` singleton 101))
382463 `shouldReturn` ([0, 100, 1, 101])
383464
384−parallelCheck :: (Semigroup (t IO Int), MonadIO (t IO))
385− => (t IO Int -> SerialT IO Int) -> Spec
386−parallelCheck t = do
465+parallelCheck :: MonadIO (t IO)
466+ => (t IO Int -> SerialT IO Int)
467+ -> (t IO Int -> t IO Int -> t IO Int)
468+ -> Spec
469+parallelCheck t f = do
387470 it "Parallel ordering left associated" $
388− (A.toList . t) (((event 4 <> event 3) <> event 2) <> event 1)
471+ (A.toList . t) (((event 4 `f` event 3) `f` event 2) `f` event 1)
389472 `shouldReturn` ([1..4])
390473
391474 it "Parallel ordering right associated" $
392− (A.toList . t) (event 4 <> (event 3 <> (event 2 <> event 1)))
475+ (A.toList . t) (event 4 `f` (event 3 `f` (event 2 `f` event 1)))
393476 `shouldReturn` ([1..4])
394477
395478 where event n = (liftIO $ threadDelay (n * 100000)) >> (return n)