OC Test your knowledge of Haskell's array primitives

Consider the following two implementations of a 'map' function for arrays. Can you guess which one of them is the fastest without running them? (Please ignore the uses of unsafeCoerce :P)

Required imports:

import Data.Primitive.Array
import Control.Monad.ST.Strict
import Unsafe.Coerce

Version 1:

mapArray1 :: forall a b. (a -> b) -> Array a -> Array b
mapArray1 f arr = runST $
  let n = length arr in
  thawArray arr 0 n >>= \m ->
  let
    go i
      | i < n = do
        x <- readArray m i
        writeArray m i $! unsafeCoerce @b @a (f x)
        go (i + 1)
      | otherwise = do
        arr' <- unsafeFreezeArray m
        return (unsafeCoerce @(Array a) @(Array b) arr')
  in
    go 0

Version 2:

mapArray2 :: forall a b. (a -> b) -> Array a -> Array b
mapArray2 f arr =
  let n = length arr in
  createArray n (unsafeCoerce @() @b ()) $ \m ->
    let
      go i
        | i < n = do
          writeArray m i $! f $! indexArray arr i
          go (i + 1)
        | otherwise = return ()
    in
      go 0
jaror,
jaror avatar

I've spent this evening trying to get conclusive benchmark results, but I have not succeeded with that yet. It seems like this is pretty difficult to benchmark. So I'd like to hear it if someone else is able to get good benchmark results.

jaror,
jaror avatar

I'm getting pretty consistent results like this now.

jaror,
jaror avatar

You may want to use the Hackage page of the Data.Primitive.Array module: https://hackage.haskell.org/package/primitive-0.8.0.0/docs/Data-Primitive-Array.html

Some relevant functions:

createArray :: Int -> a -> (forall s. MutableArray s a -> ST s ()) -> Array a

Create an array of the given size with a default value, apply the monadic function and freeze the result. If the size is 0, return emptyArray (rather than a new copy thereof).

createArray 0 _ _ = emptyArray
createArray n x f = runArray $ do
  mary <- newArray n x
  f mary
  pure mary
thawArray
  :: PrimMonad m	 
  => Array a -- ^ source
  -> Int     -- ^ offset
  -> Int     -- ^ length
  -> m (MutableArray (PrimState m) a)	 

Create a mutable array from a slice of an immutable array.

This operation makes a copy of the specified slice, so it is safe to use the immutable array afterward.

Note: The provided array should contain the full subrange specified by the two Ints, but this is not checked.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • haskell
  • DreamBathrooms
  • thenastyranch
  • ngwrru68w68
  • magazineikmin
  • khanakhh
  • rosin
  • mdbf
  • Youngstown
  • slotface
  • everett
  • cisconetworking
  • kavyap
  • tacticalgear
  • InstantRegret
  • JUstTest
  • Durango
  • osvaldo12
  • ethstaker
  • modclub
  • GTA5RPClips
  • Leos
  • cubers
  • tester
  • normalnudes
  • megavids
  • provamag3
  • anitta
  • lostlight
  • All magazines