on 430f06d help sign in
169 lines 5.4 kB history raw
1-- |
2-- Module : Streamly.Data.Array
3-- Copyright : (c) 2019 Composewell Technologies
4--
5-- License : BSD3
6-- Maintainer : streamly@composewell.com
7-- Stability : released
8-- Portability : GHC
9--
10-- This module provides APIs to create and use unboxed immutable arrays. Once
11-- created, their contents cannot be modified. Only types that are unboxable
12-- via the 'Unbox' type class can be stored in these arrays. Note that the
13-- array memory grows automatically when creating a new array, therefore, an
14-- array can be created from a variable length stream.
15--
16-- See "Streamly.Data.Array.Generic" for arrays that work for boxed types i.e.
17-- not requiring the 'Unbox' constraint.
18-- See "Streamly.Data.MutArray" for arrays that can be mutated in-place..
19--
20-- = Folding Arrays
21--
22-- Convert array to stream, and fold the stream:
23--
24-- >>> fold f arr = Stream.unfold Array.reader arr & Stream.fold f
25-- >>> fold Fold.sum (Array.fromList [1,2,3::Int])
26-- 6
27--
28-- = Transforming Arrays
29--
30-- Convert array to stream, transform, and fold back to array:
31--
32-- >>> amap f arr = Stream.unfold Array.reader arr & fmap f & Stream.fold Array.write
33-- >>> amap (+1) (Array.fromList [1,2,3::Int])
34-- fromList [2,3,4]
35--
36-- = Pinned and Unpinned Arrays
37--
38-- The array type can use both pinned and unpinned memory under the hood.
39-- Currently the array creation APIs create arrays in pinned memory but it will
40-- change to unpinned in future releases. The change should not affect users
41-- functionally unless they are directly accessing the internal memory of the
42-- array via internal APIs. As of now unpinned arrays can be created using
43-- unreleased APIs.
44--
45-- Unpinned arrays have the advantage of allowing automatic defragmentation of
46-- the memory by GC. Whereas pinned arrays have the advantage of not requiring
47-- a copy by GC. Normally you would want to use unpinned arrays. However, in
48-- some cases, for example, for long lived large data storage, and for
49-- interfacing with the operating system or foreign (non-Haskell) consumers you
50-- may want to use pinned arrays.
51--
52-- = Creating Arrays from Non-IO Streams
53--
54-- Array creation folds require 'MonadIO' because they need to sequence effects
55-- in IO streams. To operate on streams in pure Monads like 'Identity' you can
56-- morph it to IO monad as follows:
57--
58-- The 'MonadIO' based folds can be morphed to 'Identity' stream folds:
59--
60-- >>> purely = Fold.morphInner (Identity . unsafePerformIO)
61-- >>> Stream.fold (purely Array.write) $ Stream.fromList [1,2,3::Int]
62-- Identity fromList [1,2,3]
63--
64-- Since it is a pure stream we can use 'unsafePerformIO' to extract the result
65-- of fold from IO.
66--
67-- Alternatively, 'Identity' streams can be generalized to IO streams:
68--
69-- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int
70-- >>> generally = Stream.morphInner (return . runIdentity)
71-- >>> Stream.fold Array.write (generally pure :: Stream IO Int)
72-- fromList [1,2,3]
73--
74-- = Programming Tips
75--
76-- This module is designed to be imported qualified:
77--
78-- >>> import qualified Streamly.Data.Array as Array
79--
80-- Use @QuantifiedConstraints@ extension to avoid the 'Storable' constraint
81-- when using the 'Unbox' constraint.
82--
83-- For experimental APIs see "Streamly.Internal.Data.Array".
85module Streamly.Data.Array
86 (
87 -- * Imports for Examples
88 -- $setup
90 -- * The Array Type
91 A.Array
93 -- * Construction
94 -- | When performance matters, the fastest way to generate an array is
95 -- 'writeN'. 'IsList' and 'IsString' instances can be
96 -- used to conveniently construct arrays from literal values.
97 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
98 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
99 -- 'fromList' can be used to construct an array from a string literal.
101 -- Pure List APIs
102 , A.fromListN
103 , A.fromList
105 -- Monadic APIs
106 , A.writeN -- drop new
107 , A.write -- full buffer
108 , writeLastN -- drop old (ring buffer)
110 -- * Conversion
111 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
112 -- list.
113 , A.toList
115 -- * Unfolds
116 , A.reader
117 , A.readerRev
119 -- * Casting
120 , cast
121 , asBytes
123 -- * Random Access
124 , A.length
125 -- , (!!)
126 , A.getIndex
128 -- * Unbox Type Class
129 , Unbox (..)
131 -- * Deprecated
132 , read
133 , readRev
134 )
135where
137#include "inline.hs"
139import Streamly.Internal.Data.Unfold (Unfold)
140import Streamly.Internal.Data.Array as A hiding (read, readRev)
142import Streamly.Internal.Data.Unboxed (Unbox (..))
143import Prelude hiding (read)
145-- $setup
146-- >>> :m
147-- >>> :set -XFlexibleContexts
148-- >>> import Data.Function ((&))
149-- >>> import Data.Functor.Identity (Identity(..))
150-- >>> import Streamly.Data.Array (Array)
151-- >>> import Streamly.Data.Stream (Stream)
152-- >>> import System.IO.Unsafe (unsafePerformIO)
153-- >>> import qualified Streamly.Data.Array as Array
154-- >>> import qualified Streamly.Data.Fold as Fold
155-- >>> import qualified Streamly.Data.Stream as Stream
157-- | Same as 'reader'
158--
159{-# DEPRECATED read "Please use 'reader' instead" #-}
160{-# INLINE_NORMAL read #-}
161read :: (Monad m, Unbox a) => Unfold m (Array a) a
162read = reader
164-- | Same as 'readerRev'
165--
166{-# DEPRECATED readRev "Please use 'readerRev' instead" #-}
167{-# INLINE_NORMAL readRev #-}
168readRev :: (Monad m, Unbox a) => Unfold m (Array a) a
169readRev = readerRev