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 @Stream
13-- Identity a@ can be used as a replacement for @[a]@. The 'List' type in this
14-- module is just a newtype wrapper around @Stream 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) $ toStream (1 \`Cons\` Nil)
31-- To convert a 'List' to regular lists, you can use any of the following:
33-- * @toList . toStream@ and @toStream . 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(..))
69import Streamly.Internal.Data.Stream.Type (Stream)
70import Streamly.Internal.Data.Stream.Zip (ZipStream(..))
72import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
73import qualified Streamly.Internal.Data.Stream.Type as Stream
75-- We implement list as a newtype instead of a type synonym to make type
76-- inference easier when using -XOverloadedLists and -XOverloadedStrings. When
77-- using a stream type the programmer needs to specify the Monad otherwise the
78-- type remains ambiguous.
80-- XXX once we separate consM from IsStream or remove the MonadIO and
81-- MonadBaseControlIO dependency from it, then we can make this an instance of
82-- IsStream and use the regular polymorphic functions on Lists as well. Once
83-- that happens we can change the Show and Read instances as well to use "1 >:
84-- 2 >: nil" etc. or should we use a separate constructor indicating the "List"
85-- type ":>" for better inference?
87-- | @List a@ is a replacement for @[a]@.
90newtype List a = List { toStream :: Stream Identity a }
92 ( Show, Read, Eq, Ord, NFData , NFData1
93 , Semigroup, Monoid, Functor, Foldable
94 , Applicative, Traversable, Monad, IsList)
96instance (a ~ Char) => IsString (List a) where
97 {-# INLINE fromString #-}
98 fromString = List . fromList
100------------------------------------------------------------------------------
102------------------------------------------------------------------------------
104-- Note: When using the OverloadedLists extension we should be able to pattern
105-- match using the regular list contructors. OverloadedLists uses 'toList' to
106-- perform the pattern match, it should not be too bad as it works lazily in
107-- the Identity monad. We need these patterns only when not using that
110-- | An empty list constructor and pattern that matches an empty 'List'.
111-- Corresponds to '[]' for Haskell lists.
115pattern Nil <- (runIdentity . K.null . Stream.toStreamK . toStream -> True) where
116 Nil = List $ Stream.fromStreamK K.nil
120-- | A list constructor and pattern that deconstructs a 'List' into its head
121-- and tail. Corresponds to ':' for Haskell lists.
124pattern Cons :: a -> List a -> List a
126 (fmap (second (List . Stream.fromStreamK))
127 . runIdentity . K.uncons . Stream.toStreamK . toStream
133 Cons x xs = List $ Stream.cons x (toStream xs)
135{-# COMPLETE Nil, Cons #-}
137------------------------------------------------------------------------------
139------------------------------------------------------------------------------
141-- | Just like 'List' except that it has a zipping 'Applicative' instance
142-- and no 'Monad' instance.
145newtype ZipList a = ZipList { toZipStream :: ZipStream Identity a }
147 ( Show, Read, Eq, Ord, NFData , NFData1
148 , Semigroup, Monoid, Functor, Foldable
149 , Applicative, Traversable, IsList
152instance (a ~ Char) => IsString (ZipList a) where
153 {-# INLINE fromString #-}
154 fromString = ZipList . fromList
156-- | Convert a 'ZipList' to a regular 'List'
159fromZipList :: ZipList a -> List a
160fromZipList (ZipList zs) = List $ getZipStream zs
162-- | Convert a regular 'List' to a 'ZipList'
165toZipList :: List a -> ZipList a
166toZipList = ZipList . ZipStream . toStream
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