on c175cdd help sign in
170 lines 5.5 kB history raw
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveTraversable #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE PatternSynonyms #-}
5{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE UndecidableInstances #-} -- XXX
7{-# LANGUAGE ViewPatterns #-}
9-- |
10-- Module : Streamly.List
11-- Copyright : (c) 2018 Composewell Technologies
12--
13-- License : BSD3
14-- Maintainer : harendra.kumar@gmail.com
15-- Stability : experimental
16-- Portability : GHC
17--
18-- Lists are just a special case of monadic streams. The stream type @SerialT
19-- Identity a@ can be used as a replacement for @[a]@. The 'List' type in this
20-- module is just a newtype wrapper around @SerialT Identity@ for better type
21-- inference when using the 'OverloadedLists' GHC extension. @List a@ provides
22-- better performance compared to @[a]@. Standard list, string and list
23-- comprehension syntax can be used with the 'List' type by enabling
24-- 'OverloadedLists', 'OverloadedStrings' and 'MonadComprehensions' GHC
25-- extensions. If you want to replace streamly lists with standard lists, all
26-- you need to do is import these definitions:
27--
28-- @
29-- type List = []
30-- pattern Nil <- [] where Nil = []
31-- pattern Cons x xs = x : xs
32-- infixr 5 `Cons`
33-- {-\# COMPLETE Cons, Nil #-}
34-- @
35--
36-- Other than that there would be a slight difference in the 'Show' and
37-- 'Read' strings.
38--
39-- Conversion to stream types is free, any stream combinator can be used on
40-- lists by converting them to streams. However, for convenience, this module
41-- provides combinators that work directly on the 'List' type.
42--
43--
44-- @
45-- List $ S.map (+ 1) $ toSerial (1 \`Cons\` Nil)
46-- @
47--
48-- 'Data.Foldable.toList' from 'Foldable' and 'GHC.Exts.toList' and
49-- 'GHC.Exts.fromList' from 'IsList' can also be used to convert to and from
50-- standard lists.
51--
52-- See <src/docs/streamly-vs-lists.md> for more details and
53-- <src/test/PureStreams.hs> for comprehensive usage examples.
54--
55module Streamly.List
56 (
57#if __GLASGOW_HASKELL__ >= 800
58 List (.., Nil, Cons)
59#else
60 List (..)
61 , pattern Nil
62 , pattern Cons
63#endif
64 , ZipList (..)
65 , fromZipList
66 , toZipList
67 )
68where
70import Control.Arrow (second)
71import Control.DeepSeq (NFData(..), NFData1(..))
72import Data.Functor.Identity (Identity, runIdentity)
73import Data.Semigroup (Semigroup(..))
74import GHC.Exts (IsList(..), IsString(..))
76import Streamly.Streams.Serial (SerialT)
77import Streamly.Streams.Zip (ZipSerialM)
79import qualified Streamly.Streams.Prelude as P
80import qualified Streamly.Streams.StreamK as K
82-- We implement list as a newtype instead of a type synonym to make type
83-- inference easier when using -XOverloadedLists and -XOverloadedStrings. When
84-- using a stream type the programmer needs to specify the Monad otherwise the
85-- type remains ambiguous.
86--
87-- | @List a@ is a replacement for @[a]@.
88--
89-- @since 0.5.3
90newtype List a = List { toSerial :: SerialT Identity a }
91 deriving (Show, Read, Eq, Ord, NFData, NFData1
92 , Semigroup, Monoid, Functor, Foldable
93 , Applicative, Traversable, Monad)
95instance (a ~ Char) => IsString (List a) where
96 {-# INLINE fromString #-}
97 fromString = List . P.fromList
99-- GHC versions 8.0 and below cannot derive IsList
100instance IsList (List a) where
101 type (Item (List a)) = a
102 {-# INLINE fromList #-}
103 fromList = List . P.fromList
104 {-# INLINE toList #-}
105 toList = runIdentity . P.toList . toSerial
107------------------------------------------------------------------------------
108-- Patterns
109------------------------------------------------------------------------------
111-- | An empty list constructor and pattern that matches an empty 'List'.
112-- Corresponds to '[]' for Haskell lists.
113--
114-- @since 0.5.3
115pattern Nil :: List a
116pattern Nil <- (runIdentity . K.null . toSerial -> True) where
117 Nil = List K.nil
119infixr 5 `Cons`
121-- | A list constructor and pattern that deconstructs a 'List' into its head
122-- and tail. Corresponds to ':' for Haskell lists.
123--
124-- @since 0.5.3
125pattern Cons :: a -> List a -> List a
126pattern Cons x xs <-
127 (fmap (second List) . runIdentity . K.uncons . toSerial
128 -> Just (x, xs)) where
129 Cons x xs = List $ K.cons x (toSerial xs)
131#if __GLASGOW_HASKELL__ >= 802
132{-# COMPLETE Nil, Cons #-}
133#endif
135------------------------------------------------------------------------------
136-- ZipList
137------------------------------------------------------------------------------
139-- | Just like 'List' except that it has a zipping 'Applicative' instance
140-- and no 'Monad' instance.
141--
142-- @since 0.5.3
143newtype ZipList a = ZipList { toZipSerial :: ZipSerialM Identity a }
144 deriving (Show, Read, Eq, Ord, NFData, NFData1
145 , Semigroup, Monoid, Functor, Foldable
146 , Applicative, Traversable)
148instance (a ~ Char) => IsString (ZipList a) where
149 {-# INLINE fromString #-}
150 fromString = ZipList . P.fromList
152-- GHC versions 8.0 and below cannot derive IsList
153instance IsList (ZipList a) where
154 type (Item (ZipList a)) = a
155 {-# INLINE fromList #-}
156 fromList = ZipList . P.fromList
157 {-# INLINE toList #-}
158 toList = runIdentity . P.toList . toZipSerial
160-- | Convert a 'ZipList' to a regular 'List'
161--
162-- @since 0.5.3
163fromZipList :: ZipList a -> List a
164fromZipList = List . K.adapt . toZipSerial
166-- | Convert a regular 'List' to a 'ZipList'
167--
168-- @since 0.5.3
169toZipList :: List a -> ZipList a
170toZipList = ZipList . K.adapt . toSerial