{-# LANGUAGE CPP #-} -- | -- Module : Streamly.Data.Array -- Copyright : (c) 2019 Composewell Technologies -- -- License : BSD3 -- Maintainer : streamly@composewell.com -- Stability : released -- Portability : GHC -- -- Unboxed immutable arrays with streaming interfaces. -- -- Please refer to "Streamly.Internal.Data.Array" for functions that have not -- yet been released. -- -- For arrays that work on boxed types, not requiring the 'Unbox' constraint, -- please refer to "Streamly.Data.Array.Generic". For arrays that can be -- mutated in-place, please see "Streamly.Data.MutArray". module Streamly.Data.Array ( -- * Setup -- | To execute the code examples provided in this module in ghci, please -- run the following commands first. -- -- $setup -- * Overview -- $overview -- * The Array Type A.Array -- * Construction -- | When performance matters, the fastest way to generate an array is -- 'writeN'. 'IsList' and 'IsString' instances can be -- used to conveniently construct arrays from literal values. -- 'OverloadedLists' extension or 'fromList' can be used to construct an -- array from a list literal. Similarly, 'OverloadedStrings' extension or -- 'fromList' can be used to construct an array from a string literal. -- Pure List APIs , A.fromListN , A.fromList -- Monadic APIs , A.writeN -- drop new , A.write -- full buffer , writeLastN -- drop old (ring buffer) -- * Conversion -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a -- list. , A.toList -- * Unfolds , A.reader , A.readerRev -- * Casting , cast , asBytes -- * Random Access , A.length -- , (!!) , A.getIndex -- * Unbox Type Class , Unbox (..) -- * Deprecated , read , readRev ) where #include "inline.hs" import Streamly.Internal.Data.Unfold (Unfold) import Streamly.Internal.Data.Array as A hiding (read, readRev) import Streamly.Internal.Data.Unboxed (Unbox (..)) import Prelude hiding (read) #include "DocTestDataArray.hs" -- $overview -- -- This module provides APIs to create and use unboxed immutable arrays. Once -- created, their contents cannot be modified. Only types that are unboxable -- via the 'Unbox' type class can be stored in these arrays. Note that the -- array memory grows automatically when creating a new array, therefore, an -- array can be created from a variable length stream. -- -- == Folding Arrays -- -- Convert array to stream, and fold the stream: -- -- >>> fold f arr = Stream.unfold Array.reader arr & Stream.fold f -- >>> fold Fold.sum (Array.fromList [1,2,3::Int]) -- 6 -- -- == Transforming Arrays -- -- Convert array to stream, transform, and fold back to array: -- -- >>> amap f arr = Stream.unfold Array.reader arr & fmap f & Stream.fold Array.write -- >>> amap (+1) (Array.fromList [1,2,3::Int]) -- fromList [2,3,4] -- -- == Pinned and Unpinned Arrays -- -- The array type can use both pinned and unpinned memory under the hood. -- Currently the array creation APIs create arrays in pinned memory but it will -- change to unpinned in future releases. The change should not affect users -- functionally unless they are directly accessing the internal memory of the -- array via internal APIs. As of now unpinned arrays can be created using -- unreleased APIs. -- -- Unpinned arrays have the advantage of allowing automatic defragmentation of -- the memory by GC. Whereas pinned arrays have the advantage of not requiring -- a copy by GC. Normally you would want to use unpinned arrays. However, in -- some cases, for example, for long lived large data storage, and for -- interfacing with the operating system or foreign (non-Haskell) consumers you -- may want to use pinned arrays. -- -- == Creating Arrays from Non-IO Streams -- -- Array creation folds require 'MonadIO' because they need to sequence effects -- in IO streams. To operate on streams in pure Monads like 'Identity' you can -- morph it to IO monad as follows: -- -- The 'MonadIO' based folds can be morphed to 'Identity' stream folds: -- -- >>> purely = Fold.morphInner (Identity . unsafePerformIO) -- >>> Stream.fold (purely Array.write) $ Stream.fromList [1,2,3::Int] -- Identity fromList [1,2,3] -- -- Since it is a pure stream we can use 'unsafePerformIO' to extract the result -- of fold from IO. -- -- Alternatively, 'Identity' streams can be generalized to IO streams: -- -- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int -- >>> generally = Stream.morphInner (return . runIdentity) -- >>> Stream.fold Array.write (generally pure :: Stream IO Int) -- fromList [1,2,3] -- -- == Programming Tips -- -- This module is designed to be imported qualified: -- -- >>> import qualified Streamly.Data.Array as Array -- | Same as 'reader' -- {-# DEPRECATED read "Please use 'reader' instead" #-} {-# INLINE_NORMAL read #-} read :: (Monad m, Unbox a) => Unfold m (Array a) a read :: forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a read = forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a reader -- | Same as 'readerRev' -- {-# DEPRECATED readRev "Please use 'readerRev' instead" #-} {-# INLINE_NORMAL readRev #-} readRev :: (Monad m, Unbox a) => Unfold m (Array a) a readRev :: forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a readRev = forall (m :: * -> *) a. (Monad m, Unbox a) => Unfold m (Array a) a readerRev