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