HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulestreamly-core-0.2.2Haskell2010

Streamly.Data.Array

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.

  • 1 type
  • 2 classes
  • 21 values

Setup

0 declarations

To execute the code examples provided in this module in ghci, please run the following commands first.

Example6 expressions
:m:set -XFlexibleContexts:set -XMagicHashimport Data.Function ((&))import Data.Functor.Identity (Identity(..))import System.IO.Unsafe (unsafePerformIO)
Example2 expressions
import Streamly.Data.Array (Array)import Streamly.Data.Stream (Stream)
Example5 expressions
import qualified Streamly.Data.Array as Arrayimport qualified Streamly.Data.Fold as Foldimport qualified Streamly.Data.ParserK as ParserKimport qualified Streamly.Data.Stream as Streamimport qualified Streamly.Data.StreamK as StreamK

For APIs that have not been released yet.

Example2 expressions
import qualified Streamly.Internal.Data.Array as Arrayimport qualified Streamly.Internal.Data.Stream as Stream

Overview

0 declarations

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:

Example2 expressions
fold f arr = Array.read arr & Stream.fold ffold Fold.sum (Array.fromList [1,2,3::Int])6

Transforming Arrays

Convert array to stream, transform, and fold back to array:

Example2 expressions
amap f arr = Array.read arr & fmap f & Stream.fold Array.createamap (+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. The default array creation operations create unpinned arrays. IO operations automatically copy an array to pinned memory if the array passed to it is unpinned. Programmers can use appropriate pinned array generation APIs to reduce the copying if it happens.

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 otherwise the compiler may incorrectly share the array memory thinking it is pure.

See the fromPureStream unreleased API to generate an array from an Identity stream safely without using MonadIO constraint.

Note that Identity streams can be generalized to IO streams:

Example3 expressions
pure = Stream.fromList [1,2,3] :: Stream Identity Intgenerally = Stream.morphInner (return . runIdentity)Stream.fold Array.create (generally pure :: Stream IO Int)fromList [1,2,3]

Programming Tips

This module is designed to be imported qualified:

Example1 expression
import qualified Streamly.Data.Array as Array

The Array Type

1 declaration
datadata Array a
#
Instances20IsList, Eq, Ord, Read, Show, IsString, …
  • Unbox a => IsList (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Int16)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Int32)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Int64)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Int8)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Word16)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Word32)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Word64)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Word8)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Char)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Eq (Array Int)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • (Unbox a, Eq a) => Eq (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type

    If the type allows a byte-by-byte comparison this instance can be overlapped by a more specific instance that uses byteCmp. Byte comparison can be significantly faster.

  • (Unbox a, Ord a) => Ord (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • (Unbox a, Read a, Show a) => Read (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • (Show a, Unbox a) => Show (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • a ~ Char => IsString (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Unbox a => Semigroup (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type

    This should not be used for combining many or N arrays as it would copy the two arrays everytime to a new array. For coalescing multiple arrays use fromChunksK instead.

  • Unbox a => Monoid (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type
  • Serialize (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • type Item (Array a) = aDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Array.Type

Pinning & Unpinning

3 declarations

Arrays are created unpinned by default unless pinned versions of creation APIs are used. Look for APIs with pinned prefix in Streamly.Internal.Data.Array for some unreleased pinned creation APIs. If an array is to be sent to the OS without any further modification then it should be created pinned in the first place instead of pinning it later. Pinning an unpinned array has a copy overhead. OS interfacing APIs create a pinned array directly or convert an unpinned array to pinned array before sending it to the OS.

valuepin :: Array a -> IO (Array a)
#

Return a copy of the Array in pinned memory if unpinned, else return the original array.

valueunpin :: Array a -> IO (Array a)
#

Return a copy of the Array in unpinned memory if pinned, else return the original array.

Construction

0 declarations

When performance matters, the fastest way to generate an array is createOf. 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.

From Stream

valuecreate :: (MonadIO m, Unbox a) => Fold m a (Array a)
#

Fold the whole input to a single array.

Caution! Do not use this on infinite streams.

From List

valuefromListN :: Unbox a => Int -> [a] -> Array a
#

Create an Array from the first N elements of a list. The array is allocated to size N, if the list terminates before N elements then the array may hold less than N elements.

To List

1 declaration

To Stream

2 declarations

Unfolds

2 declarations

Casting

2 declarations
valuecast :: Unbox b => Array a -> Maybe (Array b)
#

Cast an array having elements of type a into an array having elements of type b. The length of the array should be a multiple of the size of the target element otherwise Nothing is returned.

Random Access

2 declarations
valuelength :: Unbox a => Array a -> Int
#

O(1) Get the length of the array i.e. the number of elements in the array.

Serialization

2 declarations
valuepinnedSerialize :: Serialize a => a -> Array Word8
#

Serialize a Haskell type to a pinned byte array. The array is allocated using pinned memory so that it can be used directly in OS APIs for writing to file or sending over the network.

Properties: 1. Identity: deserialize . pinnedSerialize == id 2. Encoded equivalence: pinnedSerialize a == pinnedSerialize a

Re-exports

2 declarations
classclass Unbox a where
#

The Unbox type class provides operations for serialization (unboxing) and deserialization (boxing) of fixed-length, non-recursive Haskell data types to and from their byte stream representation.

Unbox uses fixed size encoding, therefore, size is independent of the value, it must be determined solely by the type. This restriction makes types with Unbox instances suitable for storing in arrays. Note that sum types may have multiple constructors of different sizes, the size of a sum type is computed as the maximum required by any constructor.

The peekAt operation reads as many bytes from the mutable byte array as the size of the data type and builds a Haskell data type from these bytes. pokeAt operation converts a Haskell data type to its binary representation which consists of size bytes and then stores these bytes into the mutable byte array. These operations do not check the bounds of the array, the user of the type class is expected to check the bounds before peeking or poking.

IMPORTANT: The serialized data's byte ordering remains the same as the host machine's byte order. Therefore, it can not be deserialized from host machines with a different byte ordering.

Instances can be derived via Generics, Template Haskell, or written manually. Note that the data type must be non-recursive. WARNING! Generic and Template Haskell deriving, both hang for recursive data types. Deriving via Generics is more convenient but Template Haskell should be preferred over Generics for the following reasons:

  1. Instances derived via Template Haskell provide better and more reliable performance.

  2. Generic deriving allows only 256 fields or constructor tags whereas template Haskell has no limit.

Here is an example, for deriving an instance of this type class using generics:

Example2 expressions
import GHC.Generics (Generic):{data Object = Object    { _int0 :: Int    , _int1 :: Int    } deriving Generic:}
Example2 expressions
import Streamly.Data.MutByteArray (Unbox(..))instance Unbox Object

To derive the instance via Template Haskell:

import Streamly.Data.MutByteArray (deriveUnbox)
$(deriveUnbox [d|instance Unbox Object|])

See Streamly.Data.MutByteArray.deriveUnbox for more information on deriving using Template Haskell.

If you want to write the instance manually:

Example1 expression
:{instance Unbox Object where    sizeOf _ = 16    peekAt i arr = do       -- Check the array bounds        x0 <- peekAt i arr        x1 <- peekAt (i + 8) arr        return $ Object x0 x1    pokeAt i arr (Object x0 x1) = do       -- Check the array bounds        pokeAt i arr x0        pokeAt (i + 8) arr x1:}

Methods

  • sizeOf :: Proxy a -> Int

    Get the size. Size cannot be zero, should be at least 1 byte.

  • peekAt :: Int -> MutByteArray -> IO a

    peekAt byte-offset array reads an element of type a from the the given the byte offset in the array.

    IMPORTANT: The implementation of this interface may not check the bounds of the array, the caller must not assume that.

  • peekByteIndex :: Int -> MutByteArray -> IO a
  • pokeAt :: Int -> MutByteArray -> a -> IO ()

    pokeAt byte-offset array writes an element of type a to the the given the byte offset in the array.

    IMPORTANT: The implementation of this interface may not check the bounds of the array, the caller must not assume that.

  • pokeByteIndex :: Int -> MutByteArray -> a -> IO ()
Instances30Unbox, …
  • Unbox FingerprintDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox IntPtrDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox WordPtrDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Int16Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Int32Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Int64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Int8Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox IoSubSystemDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Word16Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Word32Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Word64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox Word8Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox BoolDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox CharDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox DoubleDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox FloatDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox IntDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox WordDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox MicroSecond64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Time.Units
  • Unbox MilliSecond64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Time.Units
  • Unbox NanoSecond64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Time.Units
  • Unbox ()Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox (FunPtr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox (Ptr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox (StablePtr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox a => Unbox (Complex a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox a => Unbox (Identity a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox a => Unbox (Down a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox a => Unbox (Ratio a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
  • Unbox a => Unbox (Const a b)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Unbox
classclass Serialize a where
#

The Serialize type class provides operations for serialization and deserialization of general Haskell data types to and from their byte stream representation.

Unlike Unbox, Serialize uses variable length encoding, therefore, it can serialize recursive and variable length data types like lists, or variable length sum types where the length of the value may vary depending on a particular constructor. For variable length data types the length is encoded along with the data.

The deserializeAt operation reads bytes from the mutable byte array and builds a Haskell data type from these bytes, the number of bytes it reads depends on the type and the encoded value it is reading. serializeAt operation converts a Haskell data type to its binary representation which must consist of as many bytes as added by the addSizeTo operation for that value and then stores these bytes into the mutable byte array. The programmer is expected to use the addSizeTo operation and allocate an array of sufficient length before calling serializeAt.

IMPORTANT: The serialized data's byte ordering remains the same as the host machine's byte order. Therefore, it can not be deserialized from host machines with a different byte ordering.

Instances can be derived via Template Haskell, or written manually.

Here is an example, for deriving an instance of this type class using template Haskell:

Example1 expression
:{data Object = Object    { _obj1 :: [Int]    , _obj2 :: Int    }:}
import Streamly.Data.MutByteArray (deriveSerialize)
$(deriveSerialize [d|instance Serialize Object|])

See Streamly.Data.MutByteArray.deriveSerialize and Streamly.Data.MutByteArray.deriveSerializeWith for more information on deriving using Template Haskell.

Here is an example of a manual instance.

Example1 expression
import Streamly.Data.MutByteArray (Serialize(..))
Example1 expression
:{instance Serialize Object where    addSizeTo acc obj = addSizeTo (addSizeTo acc (_obj1 obj)) (_obj2 obj)    deserializeAt i arr len = do         -- Check the array bounds before reading        (i1, x0) <- deserializeAt i arr len        (i2, x1) <- deserializeAt i1 arr len        pure (i2, Object x0 x1)    serializeAt i arr (Object x0 x1) = do        i1 <- serializeAt i arr x0        i2 <- serializeAt i1 arr x1        pure i2:}

Methods

  • addSizeTo :: Int -> a -> Int

    addSizeTo accum value returns accum incremented by the size of the serialized representation of value in bytes. Size cannot be zero. It should be at least 1 byte.

  • deserializeAt :: Int -> MutByteArray -> Int -> IO (Int, a)

    deserializeAt byte-offset array arrayLen deserializes a value from the given byte-offset in the array. Returns a tuple consisting of the next byte-offset and the deserialized value.

    The arrayLen passed is the entire length of the input buffer. It is to be used to check if we would overflow the input buffer when deserializing.

    Throws an exception if the operation would exceed the supplied arrayLen.

  • serializeAt :: Int -> MutByteArray -> a -> IO Int

    serializeAt byte-offset array value writes the serialized representation of the value in the array at the given byte-offset. Returns the next byte-offset.

    This is an unsafe operation, the programmer must ensure that the array has enough space available to serialize the value as determined by the addSizeTo operation.

Instances27Serialize, …
  • Serialize IntegerDefined in streamly-core-0.2.2 · Streamly.Internal.Data.MutByteArray · orphan
  • Serialize Int16Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Int32Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Int64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Int8Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Word16Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Word32Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Word64Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize Word8Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize BoolDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize CharDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize DoubleDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize FloatDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize IntDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize WordDefined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize LiftedIntegerDefined in streamly-core-0.2.2 · Streamly.Internal.Data.MutByteArray
  • Serialize ()Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize (FunPtr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize (Ptr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize (StablePtr a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize (Array a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize a => Serialize (Maybe a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.MutByteArray · orphan
  • Serialize a => Serialize (CompactList a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.TH.RecHeader
  • Serialize a => Serialize [a]Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type
  • Serialize (Proxy a)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.MutByteArray · orphan
  • (Serialize a, Serialize b) => Serialize (Either a b)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.MutByteArray · orphan
  • (Serialize a, Serialize b) => Serialize (a, b)Defined in streamly-core-0.2.2 · Streamly.Internal.Data.Serialize.Type

Deprecated

2 declarations