1{-# LANGUAGE UndecidableInstances #-}
4-- Module : Streamly.Internal.Data.List
5-- Copyright : (c) 2018 Composewell Technologies
8-- Maintainer : streamly@composewell.com
9-- Stability : pre-release
12-- Lists are just a special case of monadic streams. The stream type @SerialT
13-- Identity a@ can be used as a replacement for @[a]@. The 'List' type in this
14-- module is just a newtype wrapper around @SerialT Identity@ for better type
15-- inference when using the 'OverloadedLists' GHC extension. @List a@ provides
16-- better performance compared to @[a]@. Standard list, string and list
17-- comprehension syntax can be used with the 'List' type by enabling
18-- 'OverloadedLists', 'OverloadedStrings' and 'MonadComprehensions' GHC
19-- extensions. There would be a slight difference in the 'Show' and 'Read'
20-- strings of streamly list as compared to regular lists.
22-- Conversion to stream types is free, any stream combinator can be used on
23-- lists by converting them to streams. However, for convenience, this module
24-- provides combinators that work directly on the 'List' type.
28-- List $ S.map (+ 1) $ toSerial (1 \`Cons\` Nil)
31-- To convert a 'List' to regular lists, you can use any of the following:
33-- * @toList . toSerial@ and @toSerial . fromList@
34-- * 'Data.Foldable.toList' from "Data.Foldable"
35-- * 'GHC.Exts.toList' and 'GHC.Exts.fromList' from 'IsList' in "GHC.Exts"
37-- If you have made use of 'Nil' and 'Cons' constructors in the code and you
38-- want to replace streamly lists with standard lists, all you need to do is
39-- import these definitions:
43-- pattern Nil <- [] where Nil = []
44-- pattern Cons x xs = x : xs
46-- {-\# COMPLETE Cons, Nil #-}
49-- See <src/docs/streamly-vs-lists.md> for more details and
50-- <src/test/PureStreams.hs> for comprehensive usage examples.
52module Streamly.Internal.Data.List
56 -- XXX we may want to use rebindable syntax for variants instead of using
57 -- different types (applicative do and apWith).
64import Control.Arrow (second)
65import Control.DeepSeq (NFData(..))
66import Control.DeepSeq (NFData1(..))
67import Data.Functor.Identity (Identity, runIdentity)
68import GHC.Exts (IsList(..), IsString(..))
69#if __GLASGOW_HASKELL__ < 808
70import Data.Semigroup (Semigroup(..))
72import Streamly.Internal.Data.Stream.Serial (SerialT(..))
73import Streamly.Internal.Data.Stream.Zip (ZipSerialM(..))
75import qualified Streamly.Internal.Data.Stream.Serial as Serial
76import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
78-- We implement list as a newtype instead of a type synonym to make type
79-- inference easier when using -XOverloadedLists and -XOverloadedStrings. When
80-- using a stream type the programmer needs to specify the Monad otherwise the
81-- type remains ambiguous.
83-- XXX once we separate consM from IsStream or remove the MonadIO and
84-- MonadBaseControlIO dependency from it, then we can make this an instance of
85-- IsStream and use the regular polymorphic functions on Lists as well. Once
86-- that happens we can change the Show and Read instances as well to use "1 >:
87-- 2 >: nil" etc. or should we use a separate constructor indicating the "List"
88-- type ":>" for better inference?
90-- | @List a@ is a replacement for @[a]@.
93newtype List a = List { toSerial :: SerialT Identity a }
95 ( Show, Read, Eq, Ord, NFData , NFData1
96 , Semigroup, Monoid, Functor, Foldable
97 , Applicative, Traversable, Monad)
99instance (a ~ Char) => IsString (List a) where
100 {-# INLINE fromString #-}
101 fromString = List . fromList
103-- GHC versions 8.0 and below cannot derive IsList
104instance IsList (List a) where
105 type (Item (List a)) = a
106 {-# INLINE fromList #-}
107 fromList = List . fromList
108 {-# INLINE toList #-}
109 toList = toList . toSerial
111------------------------------------------------------------------------------
113------------------------------------------------------------------------------
115-- Note: When using the OverloadedLists extension we should be able to pattern
116-- match using the regular list contructors. OverloadedLists uses 'toList' to
117-- perform the pattern match, it should not be too bad as it works lazily in
118-- the Identity monad. We need these patterns only when not using that
121-- | An empty list constructor and pattern that matches an empty 'List'.
122-- Corresponds to '[]' for Haskell lists.
126pattern Nil <- (runIdentity . K.null . getSerialT . toSerial -> True) where
127 Nil = List $ SerialT K.nil
131-- | A list constructor and pattern that deconstructs a 'List' into its head
132-- and tail. Corresponds to ':' for Haskell lists.
135pattern Cons :: a -> List a -> List a
137 (fmap (second (List . SerialT))
138 . runIdentity . K.uncons . getSerialT . toSerial
144 Cons x xs = List $ Serial.cons x (toSerial xs)
146{-# COMPLETE Nil, Cons #-}
148------------------------------------------------------------------------------
150------------------------------------------------------------------------------
152-- | Just like 'List' except that it has a zipping 'Applicative' instance
153-- and no 'Monad' instance.
156newtype ZipList a = ZipList { toZipSerial :: ZipSerialM Identity a }
158 ( Show, Read, Eq, Ord, NFData , NFData1
159 , Semigroup, Monoid, Functor, Foldable
160 , Applicative, Traversable
163instance (a ~ Char) => IsString (ZipList a) where
164 {-# INLINE fromString #-}
165 fromString = ZipList . fromList
167-- GHC versions 8.0 and below cannot derive IsList
168instance IsList (ZipList a) where
169 type (Item (ZipList a)) = a
170 {-# INLINE fromList #-}
171 fromList = ZipList . fromList
172 {-# INLINE toList #-}
173 toList = toList . toZipSerial
175-- | Convert a 'ZipList' to a regular 'List'
178fromZipList :: ZipList a -> List a
179fromZipList (ZipList zs) = List $ SerialT $ getZipSerialM zs
181-- | Convert a regular 'List' to a 'ZipList'
184toZipList :: List a -> ZipList a
185toZipList = ZipList . ZipSerialM . getSerialT . toSerial
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list