Skip to content

Commit 8e71351

Browse files
committed
More changes
* Add notes. * Improve some of the types. * Drop `PolyKinds`. I added it because of unclear thinking, and I don't think any of this benefits meaningfully from having it.
1 parent e8685d6 commit 8e71351

File tree

2 files changed

+94
-29
lines changed

2 files changed

+94
-29
lines changed

Data/Primitive/Array.hs

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, DeriveDataTypeable, BangPatterns #-}
22
{-# LANGUAGE RankNTypes #-}
33
{-# LANGUAGE TypeFamilies #-}
4-
#if __GLASGOW_HASKELL__ >= 706
5-
{-# LANGUAGE PolyKinds #-}
6-
#endif
74

85
-- |
96
-- Module : Data.Primitive.Array
@@ -344,6 +341,7 @@ emptyArray# _ = case emptyArray of Array ar -> ar
344341
{-# NOINLINE emptyArray# #-}
345342
#endif
346343

344+
347345
die :: String -> String -> a
348346
die fun problem = error $ "Data.Primitive.Array." ++ fun ++ ": " ++ problem
349347

@@ -818,24 +816,72 @@ runArrays m = runST $ m >>= traverse unsafeFreezeArray
818816
-- constraint. To produce arrays of varying types, use 'runArraysHetOf'.
819817
runArraysOf
820818
:: (forall s1 s2.
821-
(MutableArray s1 a -> ST s2 (Array a)) -> t (MutableArray s1 a) -> ST s2 (u (Array a)))
822-
-> (forall s. ST s (t (MutableArray s a)))
823-
-> u (Array a)
819+
(MutableArray s1 a -> ST s2 (Array a)) -> t (mut s1 x) -> ST s2 u)
820+
-> (forall s. ST s (t (mut s x)))
821+
-> u
822+
-- See notes below
824823
runArraysOf trav m = runST $ m >>= trav unsafeFreezeArray
825824

826825
{-
826+
Why do I believe 'runArraysOf' is safe? The key safety property is
827+
that we must never modify an array after it is frozen. The first
828+
thing we do is run the given action, producing something of type
829+
830+
t (mut s x)
831+
832+
and passing it to trav. We need to make sure that trav just applies
833+
its function argument (unsafeFreezeArray) to any MutableArrays that
834+
may contain/produce, and doesn't modify them in any other ways. Consider
835+
the type of trav:
836+
837+
trav :: forall s1 s2.
838+
(MutableArray s1 a -> ST s2 (Array a))
839+
-> t (mut s1 x) -> ST s2 u
840+
841+
trav operates in the state thread labeled s2. We don't let it know that
842+
the mutable arrays it handles live in the same thread! They're off in
843+
s1, a whole different universe. So trav can only apply the freeze it's
844+
passed, or perform whatever actions may ride in on t (mut s x). Can
845+
the latter happen? Imagine something like
846+
847+
data T :: Type -> Type where
848+
T :: ST s (MutableArray s x) -> T (MutableArray s x)
849+
850+
Can trav pull this open and run the action? No! The state thread in
851+
T matches the array in T, but it doesn't match the state thread trav
852+
lives in, so trav can't do anything whatsoever with it.
853+
854+
-----
855+
856+
It's annoying that @t@ takes a @mut s1 x@ argument instead
857+
of just an @s1@ argument, but this allows 'runArraysOf' to be used directly
858+
with 'traverse'. The cleaner version can be implemented efficiently on
859+
top in the following rather disgusting manner:
860+
861+
runArraysOf'
862+
:: (forall s1 s2.
863+
(MutableArray s1 a -> ST s2 (Array a)) -> t s1 -> ST s2 u)
864+
-> (forall s. ST s (t s))
865+
-> u
866+
runArraysOf' trav m = runArraysOf ((. unBar) #. trav) (coerce m)
867+
868+
newtype Bar t x = Bar {unBar :: t (Yuck x)}
869+
type family Yuck x where
870+
Yuck (_ s _) = s
871+
872+
-------
873+
827874
I initially thought we'd need a function like
828875
829876
runArraysOfThen
830877
:: (forall s1 s2.
831-
(MutableArray s1 a -> Compose (ST s2) q r) -> t (MutableArray s1 a) -> Compose (ST s2) q (u r))
878+
(MutableArray s1 a -> Compose (ST s2) q r) -> t (MutableArray s1 a) -> Compose (ST s2) q u)
832879
-> (Array a -> q r)
833880
-> (forall s. ST s (t (MutableArray s a)))
834-
-> q (u r)
881+
-> q u
835882
836-
to allow users to traverse over the generated arrays. But because 'runArraysOf'
837-
allows the traversal function to know that it is producing values of type
838-
@Array a@, one could just write
883+
to allow users to traverse over the generated arrays. But in fact,
884+
one could just write
839885
840886
runArraysOfThen trav post m = getConst $
841887
runArraysOf (\f -> coerce . getCompose . (trav (Compose . fmap post . f))) m
@@ -886,21 +932,42 @@ clearly not necessary.
886932
-- @
887933
-- runArraysHetOfThen
888934
-- :: (forall s1 s2.
889-
-- ((forall x. MutableArray s1 x -> Compose (ST s2) q (r x)) -> t (MutableArray s1) -> Compose (ST s2) q (u r)))
935+
-- ( (forall x. MutableArray s1 x -> Compose (ST s2) q (r x))
936+
-- -> t (mut s1) -> Compose (ST s2) q u))
890937
-- -- ^ A rank-2 traversal
891938
-- -> (forall x. Array x -> q (r x))
892939
-- -- ^ A function to traverse over the container of 'Array's
893-
-- -> (forall s. ST s (t (MutableArray s)))
940+
-- -> (forall s. ST s (t (mut s)))
894941
-- -- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
895-
-- -> q (u r)
942+
-- -> q u
896943
-- runArraysHetOfThen trav post m = getConst $
897944
-- runArraysHetOf (\f -> coerce . getCompose . trav (Compose . fmap post . f)) m
898945
-- @
899946
runArraysHetOf
900947
:: (forall s1 s2.
901-
((forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (MutableArray s1) -> ST s2 (u Array)))
948+
((forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1) -> ST s2 u))
902949
-- ^ A rank-2 traversal
903-
-> (forall s. ST s (t (MutableArray s)))
950+
-> (forall s. ST s (t (mut s)))
904951
-- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
905-
-> u Array
952+
-> u
906953
runArraysHetOf trav m = runST $ m >>= trav unsafeFreezeArray
954+
955+
{-
956+
This alternative version is arguably prettier, but it's not compatible
957+
with the traversal functions from rank2types or compdata for the same reason
958+
that the prettier version of 'runArraysOf' isn't compatible with 'traverse'.
959+
It can be implemented with a bit of ugliness.
960+
961+
runArraysHetOf'
962+
:: (forall s1 s2.
963+
((forall x. MutableArray s1 x -> ST s2 (Array x)) -> t s1 -> ST s2 u))
964+
-- ^ A rank-2 traversal
965+
-> (forall s. ST s (t s))
966+
-- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
967+
-> u
968+
runArraysHetOf' trav m = runArraysHetOf (\f -> trav f . unBaz) (coerce m)
969+
970+
type family Gross ms where
971+
Gross (_ s) = s
972+
newtype Baz t ms = Baz {unBaz :: t (Gross ms)}
973+
-}

Data/Primitive/SmallArray.hs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
{-# LANGUAGE DeriveDataTypeable #-}
88
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
99
{-# LANGUAGE BangPatterns #-}
10-
#if __GLASGOW_HASKELL__ >= 706
11-
{-# LANGUAGE PolyKinds #-}
12-
#endif
1310

1411
-- |
1512
-- Module : Data.Primitive.SmallArray
@@ -967,9 +964,9 @@ runSmallArrays m = runST $ m >>= traverse unsafeFreezeSmallArray
967964
runSmallArraysOf
968965
:: (forall s1 s2.
969966
(SmallMutableArray s1 a -> ST s2 (SmallArray a))
970-
-> t (SmallMutableArray s1 a) -> ST s2 (u (SmallArray a)))
971-
-> (forall s. ST s (t (SmallMutableArray s a)))
972-
-> u (SmallArray a)
967+
-> t (mut s1 x) -> ST s2 u)
968+
-> (forall s. ST s (t (mut s x)))
969+
-> u
973970
runSmallArraysOf trav m = runST $ m >>= trav unsafeFreezeSmallArray
974971

975972
-- | Create arbitrarily many arrays that may have different types. For
@@ -1016,22 +1013,23 @@ runSmallArraysOf trav m = runST $ m >>= trav unsafeFreezeSmallArray
10161013
-- @
10171014
-- runSmallArraysHetOfThen
10181015
-- :: (forall s1 s2.
1019-
-- ((forall x. MutableArray s1 x -> Compose (ST s2) q (r x)) -> t (MutableArray s1) -> Compose (ST s2) q (u r)))
1016+
-- ( (forall x. SmallMutableArray s1 x -> Compose (ST s2) q (r x))
1017+
-- -> t (mut s1) -> Compose (ST s2) q u))
10201018
-- -- ^ A rank-2 traversal
10211019
-- -> (forall x. SmallArray x -> q (r x))
10221020
-- -- ^ A function to traverse over a container of 'SmallArray's
1023-
-- -> (forall s. ST s (t (SmallMutableArray s)))
1021+
-- -> (forall s. ST s (t (mut s)))
10241022
-- -- ^ An 'ST' action producing a rank-2 container of 'SmallMutableArray's.
1025-
-- -> q (u r)
1023+
-- -> q u
10261024
-- runSmallArraysHetOfThen trav post m = getConst $
10271025
-- runSmallArraysHetOf (\f -> coerce . getCompose . trav (Compose . fmap post . f)) m
10281026
-- @
10291027
runSmallArraysHetOf
10301028
:: (forall s1 s2.
10311029
((forall x. SmallMutableArray s1 x -> ST s2 (SmallArray x))
1032-
-> t (SmallMutableArray s1) -> ST s2 (u SmallArray)))
1030+
-> t (mut s1) -> ST s2 u))
10331031
-- ^ A rank-2 traversal
1034-
-> (forall s. ST s (t (SmallMutableArray s)))
1032+
-> (forall s. ST s (t (mut s)))
10351033
-- ^ An 'ST' action producing a rank-2 container of 'MutableArray's.
1036-
-> u SmallArray
1034+
-> u
10371035
runSmallArraysHetOf f m = runST $ m >>= f unsafeFreezeSmallArray

0 commit comments

Comments
 (0)