Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are mutable arrays implemented in Haskell?

I've read many research papers on this topic, and they usually argue that arrays are implemented using Monads. But none of these papers gave a clear definition of how the "type" Array itself should be defined, they only gave definitions for the functions using monads to access or modify this type. How are arrays, having O(1) time to access or modify an indexed element, implemented in Haskell ?! (such as STUArray and MArray)

like image 344
is7s Avatar asked Apr 24 '11 20:04

is7s


People also ask

Does Haskell have arrays?

Although Haskell has an incremental array update operator, the main thrust of the array facility is monolithic. Arrays are not part of the Standard Prelude---the standard library contains the array operators. Any module using arrays must import the Array module.

Are lists mutable in Haskell?

All Haskell values are immutable. You can't change a value that's bound to a name (you can shadow them in GHCi, but that's a slightly different thing). If you want to achieve true1 mutability, you need an immutable reference to mutable data.

Are lists immutable in Haskell?

Haskell "defaults to" immutable single-linked lists, but also supports both immutable and mutable arrays.


1 Answers

How are arrays, having O(1) time to access or modify an indexed element, implemented in Haskell

They are implemented via primitive operations in the runtime system for memory reads and writes.

The safety of the side effecting action of destructively writing to memory is ensured via the use of monads to linearize access to the mutable state.

Looking at the primitive package for Haskell arrays (in IO or ST), you can see that the implementations is in terms of GHC's primops:

-- | Create a new mutable array of the specified size and initialise all -- elements with the given value. newArray :: PrimMonad m => Int -> a -> m (MutableArray (PrimState m) a) newArray (I# n#) x = primitive    (\s# -> case newArray# n# x s# of              (# s'#, arr# #) -> (# s'#, MutableArray arr# #))  -- | Read a value from the array at the given index. readArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> m a readArray (MutableArray arr#) (I# i#) = primitive (readArray# arr# i#)  -- | Write a value to the array at the given index. writeArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> a -> m () writeArray (MutableArray arr#) (I# i#) x = primitive_ (writeArray# arr# i# x) 

That is, in terms of:

  • newArray#
  • readArray#
  • writeArray#

which are primitive (hardware accelerated ;) services for operating on memory provided by the language runtime.

Mechanisms for giving type safety to destructive memory effects were introduced to Haskell by the Launchbury and Peyton-Jones paper, Lazy Functional State Threads, which introduces the ST monad and primitives for mutable arrays.

like image 50
Don Stewart Avatar answered Sep 28 '22 02:09

Don Stewart