Skip to content

Commit 9f9894c

Browse files
committed
Heterogeneous array creation
Create arbitrarily many arrays of arbitrarily many types from one `ST` action. Closes #103
1 parent c40a0d5 commit 9f9894c

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

Data/Primitive/Array.hs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module Data.Primitive.Array (
1717
Array(..), MutableArray(..),
1818

1919
newArray, readArray, writeArray, indexArray, indexArrayM,
20-
freezeArray, thawArray, runArray,
20+
freezeArray, thawArray, runArray, runArrays, runArraysHetOf,
2121
unsafeFreezeArray, unsafeThawArray, sameMutableArray,
2222
copyArray, copyMutableArray,
2323
cloneArray, cloneMutableArray,
@@ -341,7 +341,6 @@ emptyArray# _ = case emptyArray of Array ar -> ar
341341
{-# NOINLINE emptyArray# #-}
342342
#endif
343343

344-
345344
die :: String -> String -> a
346345
die fun problem = error $ "Data.Primitive.Array." ++ fun ++ ": " ++ problem
347346

@@ -798,3 +797,57 @@ instance (Typeable s, Typeable a) => Data (MutableArray s a) where
798797
toConstr _ = error "toConstr"
799798
gunfold _ _ = error "gunfold"
800799
dataTypeOf _ = mkNoRepType "Data.Primitive.Array.MutableArray"
800+
801+
-- | Create any number of arrays of the same type within an arbitrary
802+
-- 'Traversable' context. This will often be useful with traversables
803+
-- like @(c,)@, @'Either' e@, @'Compose' (c,) ('Either' e)@, and
804+
-- @'Compose' ('Either' e) (c,)@. For a more general version, see
805+
-- 'runArraysHetOf'.
806+
runArrays
807+
:: Traversable t
808+
=> (forall s. ST s (t (MutableArray s a)))
809+
-> t (Array a)
810+
runArrays m = runST $ m >>= traverse unsafeFreezeArray
811+
812+
-- | Create arbitrarily many arrays that may have different types.
813+
-- For a simpler but less general version, see 'runArrays'.
814+
--
815+
-- === __Examples__
816+
--
817+
-- ==== @'runArrays'@
818+
--
819+
-- @
820+
-- newtype Ha t a v = Ha {unHa :: t (v a)}
821+
-- runArrays m = unHa $ runArraysHetOf (\f (Ha t) -> Ha <$> traverse f t) (Ha <$> m)
822+
-- @
823+
--
824+
-- ==== @unzipArray@
825+
--
826+
-- @
827+
-- unzipArray :: Array (a, b) -> (Array a, Array b)
828+
-- unzipArray ar =
829+
-- unPair $ runArraysHetOf traversePair $ do
830+
-- xs <- newArray sz undefined
831+
-- ys <- newArray sz undefined
832+
-- let go k
833+
-- | k == sz = pure (Pair (xs, ys))
834+
-- | otherwise = do
835+
-- (x,y) <- indexArrayM ar k
836+
-- writeArray xs k x
837+
-- writeArray ys k y
838+
-- go (k + 1)
839+
-- go 0
840+
-- where sz = sizeofArray ar
841+
--
842+
-- data Pair ab v where
843+
-- Pair :: {unPair :: (v a, v b)} -> Pair (a,b) v
844+
--
845+
-- traversePair :: Applicative h => (forall x. f x -> h (g x)) -> Pair ab f -> h (Pair ab g)
846+
-- traversePair f (Pair (xs, ys)) = liftA2 (\x y -> Pair (x,y)) (f xs) (f ys)
847+
-- @
848+
runArraysHetOf
849+
:: (forall h f g.
850+
(Applicative h => (forall x. f x -> h (g x)) -> t f -> h (u g))) -- ^ A rank-2 traversal
851+
-> (forall s. ST s (t (MutableArray s))) -- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
852+
-> u Array
853+
runArraysHetOf f m = runST $ m >>= f unsafeFreezeArray

Data/Primitive/SmallArray.hs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ module Data.Primitive.SmallArray
5252
, unsafeFreezeSmallArray
5353
, thawSmallArray
5454
, runSmallArray
55+
, runSmallArrays
56+
, runSmallArraysHetOf
5557
, unsafeThawSmallArray
5658
, sizeofSmallArray
5759
, sizeofSmallMutableArray
@@ -940,3 +942,57 @@ smallArrayFromListN n l = SmallArray (Array.fromListN n l)
940942
-- | Create a 'SmallArray' from a list.
941943
smallArrayFromList :: [a] -> SmallArray a
942944
smallArrayFromList l = smallArrayFromListN (length l) l
945+
946+
-- | Create any number of arrays of the same type within an arbitrary
947+
-- 'Traversable' context. This will often be useful with traversables
948+
-- like @(c,)@, @'Either' e@, @'Compose' (c,) ('Either' e)@, and
949+
-- @'Compose' ('Either' e) (c,)@. For a more general version, see
950+
-- 'runArraysHetOf'.
951+
runSmallArrays
952+
:: Traversable t
953+
=> (forall s. ST s (t (SmallMutableArray s a)))
954+
-> t (SmallArray a)
955+
runSmallArrays m = runST $ m >>= traverse unsafeFreezeSmallArray
956+
957+
-- | Create arbitrarily many arrays that may have different types. For
958+
-- a simpler but less general version, see 'runArrays'.
959+
--
960+
-- === __Examples__
961+
--
962+
-- ==== @'runSmallArrays'@
963+
--
964+
-- @
965+
-- newtype Ha t a v = Ha {unHa :: t (v a)}
966+
-- runSmallArrays m = unHa $ runSmallArraysHetOf (\f (Ha t) -> Ha <$> traverse f t) (Ha <$> m)
967+
-- @
968+
--
969+
-- ==== @unzipSmallArray@
970+
--
971+
-- @
972+
-- unzipSmallArray :: Array (a, b) -> (Array a, Array b)
973+
-- unzipSmallArray ar =
974+
-- unPair $ runSmallArraysHetOf traversePair $ do
975+
-- xs <- newSmallArray sz undefined
976+
-- ys <- newSmallArray sz undefined
977+
-- let go k
978+
-- | k == sz = pure (Pair (xs, ys))
979+
-- | otherwise = do
980+
-- (x,y) <- indexSmallArrayM ar k
981+
-- writeSmallArray xs k x
982+
-- writeSmallArray ys k y
983+
-- go (k + 1)
984+
-- go 0
985+
-- where sz = sizeofSmallArray ar
986+
--
987+
-- data Pair ab v where
988+
-- Pair :: {unPair :: (v a, v b)} -> Pair (a,b) v
989+
--
990+
-- traversePair :: Applicative h => (forall x. f x -> h (g x)) -> Pair ab f -> h (Pair ab g)
991+
-- traversePair f (Pair (xs, ys)) = liftA2 (\x y -> Pair (x,y)) (f xs) (f ys)
992+
-- @
993+
runSmallArraysHetOf
994+
:: (forall h f g.
995+
(Applicative h => (forall x. f x -> h (g x)) -> t f -> h (u g))) -- ^ A rank-2 traversal
996+
-> (forall s. ST s (t (SmallMutableArray s))) -- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
997+
-> u SmallArray
998+
runSmallArraysHetOf f m = runST $ m >>= f unsafeFreezeSmallArray

0 commit comments

Comments
 (0)