2525-- | `Data.Foldable.or` tests whether an array of `Boolean` values contains
2626-- | at least one `true` value.
2727-- | * `Traversable`, which provides the PureScript version of a for-loop,
28- -- | allowing you to iterate over an array and accumulate effects.
28+ -- | allowing you to STAI. iterate over an array and accumulate effects.
2929-- |
3030module Data.Array
3131 ( fromFoldable
@@ -90,7 +90,9 @@ module Data.Array
9090 , groupBy
9191
9292 , nub
93+ , nubEq
9394 , nubBy
95+ , nubByEq
9496 , union
9597 , unionBy
9698 , delete
@@ -114,22 +116,24 @@ module Data.Array
114116 ) where
115117
116118import Prelude
119+
117120import Control.Alt ((<|>))
118121import Control.Alternative (class Alternative )
119122import Control.Lazy (class Lazy , defer )
120123import Control.Monad.Rec.Class (class MonadRec , Step (..), tailRecM2 )
121- import Control.Monad.ST (pureST )
122- import Data.Array.ST (unsafeFreeze , emptySTArray , pokeSTArray , pushSTArray , modifySTArray , withArray )
123- import Data.Array.ST.Iterator (iterator , iterate , pushWhile )
124+ import Control.Monad.ST as ST
125+ import Data.Array.ST as STA
126+ import Data.Array.ST.Iterator as STAI
127+ import Data.Array.NonEmpty.Internal (NonEmptyArray )
124128import Data.Foldable (class Foldable , foldl , foldr , traverse_ )
125129import Data.Foldable (foldl , foldr , foldMap , fold , intercalate , elem , notElem , find , findMap , any , all ) as Exports
126130import Data.Maybe (Maybe (..), maybe , isJust , fromJust )
127- import Data.NonEmpty (NonEmpty , (:|))
128131import Data.Traversable (scanl , scanr ) as Exports
129132import Data.Traversable (sequence , traverse )
130- import Data.Tuple (Tuple (..), uncurry )
133+ import Data.Tuple (Tuple (..), fst , snd )
131134import Data.Unfoldable (class Unfoldable , unfoldr )
132135import Partial.Unsafe (unsafePartial )
136+ import Unsafe.Coerce (unsafeCoerce )
133137
134138-- | Convert an `Array` into an `Unfoldable` structure.
135139toUnfoldable :: forall f . Unfoldable f => Array ~> f
@@ -299,7 +303,7 @@ last xs = xs !! (length xs - 1)
299303-- | `Nothing` if the array is empty
300304-- |
301305-- | ```purescript
302- -- | tail [1, 2, 3, 4] = Just [2, 3, 4]
306+ -- | tail [1, 2, 3, 4] = Just [2, 3, 4]
303307-- | tail [] = Nothing
304308-- | ```
305309-- |
@@ -348,7 +352,7 @@ foreign import uncons'
348352-- | Break an array into its last element and all preceding elements.
349353-- |
350354-- | ```purescript
351- -- | unsnoc [1, 2, 3] = Just {init: [1, 2], last: 3}
355+ -- | unsnoc [1, 2, 3] = Just {init: [1, 2], last: 3}
352356-- | unsnoc [] = Nothing
353357-- | ```
354358-- |
@@ -511,7 +515,7 @@ foreign import _updateAt
511515-- | array, or returning `Nothing` if the index is out of bounds.
512516-- |
513517-- | ```purescript
514- -- | modifyAt 1 toUpper ["Hello", "World"] = Just ["Hello", "WORLD"]
518+ -- | modifyAt 1 toUpper ["Hello", "World"] = Just ["Hello", "WORLD"]
515519-- | modifyAt 10 toUpper ["Hello", "World"] = Nothing
516520-- | ```
517521-- |
@@ -525,10 +529,10 @@ modifyAt i f xs = maybe Nothing go (xs !! i)
525529-- | index is out-of-bounds.
526530-- |
527531-- | ```purescript
528- -- | alterAt 1 (stripSuffix $ Pattern "!") ["Hello", "World!"]
532+ -- | alterAt 1 (stripSuffix $ Pattern "!") ["Hello", "World!"]
529533-- | = Just ["Hello", "World"]
530534-- |
531- -- | alterAt 1 (stripSuffix $ Pattern "!!!!!") ["Hello", "World!"]
535+ -- | alterAt 1 (stripSuffix $ Pattern "!!!!!") ["Hello", "World!"]
532536-- | = Just ["Hello"]
533537-- |
534538-- | alterAt 10 (stripSuffix $ Pattern "!") ["Hello", "World!"] = Nothing
@@ -629,7 +633,7 @@ mapMaybe f = concatMap (maybe [] singleton <<< f)
629633-- | ```
630634-- |
631635catMaybes :: forall a . Array (Maybe a ) -> Array a
632- catMaybes = mapMaybe id
636+ catMaybes = mapMaybe identity
633637
634638-- | Apply a function to each element in an array, supplying a generated
635639-- | zero-based index integer along with the element, creating an array
@@ -656,7 +660,7 @@ mapWithIndex f xs =
656660-- |
657661updateAtIndices :: forall t a . Foldable t => t (Tuple Int a ) -> Array a -> Array a
658662updateAtIndices us xs =
659- pureST ( withArray (\res -> traverse_ (uncurry $ pokeSTArray res) us) xs)
663+ ST .run ( STA . withArray (\res -> traverse_ (\( Tuple i a) -> STA .poke i a res) us) xs)
660664
661665-- | Apply a function to the element at the specified indices,
662666-- | creating a new array. Out-of-bounds indices will have no effect.
@@ -669,7 +673,7 @@ updateAtIndices us xs =
669673-- |
670674modifyAtIndices :: forall t a . Foldable t => t Int -> (a -> a ) -> Array a -> Array a
671675modifyAtIndices is f xs =
672- pureST ( withArray (\res -> traverse_ (\i -> modifySTArray res i f) is) xs)
676+ ST .run ( STA . withArray (\res -> traverse_ (\i -> STA .modify i f res ) is) xs)
673677
674678-- ------------------------------------------------------------------------------
675679-- Sorting ---------------------------------------------------------------------
@@ -836,15 +840,15 @@ span p arr =
836840-- | ```purescript
837841-- | group [1,1,2,2,1] == [NonEmpty 1 [1], NonEmpty 2 [2], NonEmpty 1 []]
838842-- | ```
839- group :: forall a . Eq a => Array a -> Array (NonEmpty Array a )
843+ group :: forall a . Eq a => Array a -> Array (NonEmptyArray a )
840844group xs = groupBy eq xs
841845
842846-- | Sort and then group the elements of an array into arrays.
843847-- |
844848-- | ```purescript
845849-- | group' [1,1,2,2,1] == [NonEmpty 1 [1,1],NonEmpty 2 [2]]
846850-- | ```
847- group' :: forall a . Ord a => Array a -> Array (NonEmpty Array a )
851+ group' :: forall a . Ord a => Array a -> Array (NonEmptyArray a )
848852group' = group <<< sort
849853
850854-- | Group equal, consecutive elements of an array into arrays, using the
@@ -855,38 +859,75 @@ group' = group <<< sort
855859-- | = [NonEmpty 1 [3], NonEmpty 2 [] , NonEmpty 4 [], NonEmpty 3 [3]]
856860-- | ```
857861-- |
858- groupBy :: forall a . (a -> a -> Boolean ) -> Array a -> Array (NonEmpty Array a )
862+ groupBy :: forall a . (a -> a -> Boolean ) -> Array a -> Array (NonEmptyArray a )
859863groupBy op xs =
860- pureST do
861- result <- emptySTArray
862- iter <- iterator (xs !! _)
863- iterate iter \x -> void do
864- sub <- emptySTArray
865- pushWhile (op x) iter sub
866- sub_ <- unsafeFreeze sub
867- pushSTArray result (x :| sub_)
868- unsafeFreeze result
864+ ST .run do
865+ result <- STA .empty
866+ iter <- STAI .iterator (xs !! _)
867+ STAI .iterate iter \x -> void do
868+ sub <- STA .empty
869+ STAI .pushWhile (op x) iter sub
870+ _ <- STA .push x sub
871+ grp <- STA .unsafeFreeze sub
872+ STA .push ((unsafeCoerce :: Array ~> NonEmptyArray ) grp) result
873+ STA .unsafeFreeze result
869874
870875-- | Remove the duplicates from an array, creating a new array.
871876-- |
872877-- | ```purescript
873878-- | nub [1, 2, 1, 3, 3] = [1, 2, 3]
874879-- | ```
875880-- |
876- nub :: forall a . Eq a => Array a -> Array a
877- nub = nubBy eq
881+ nub :: forall a . Ord a => Array a -> Array a
882+ nub = nubBy compare
883+
884+ -- | Remove the duplicates from an array, creating a new array.
885+ -- |
886+ -- | This less efficient version of `nub` only requires an `Eq` instance.
887+ -- |
888+ -- | ```purescript
889+ -- | nubEq [1, 2, 1, 3, 3] = [1, 2, 3]
890+ -- | ```
891+ -- |
892+ nubEq :: forall a . Eq a => Array a -> Array a
893+ nubEq = nubByEq eq
894+
895+ -- | Remove the duplicates from an array, where element equality is determined
896+ -- | by the specified ordering, creating a new array.
897+ -- |
898+ -- | ```purescript
899+ -- | nubBy compare [1, 3, 4, 2, 2, 1] == [1, 3, 4, 2]
900+ -- | ```
901+ -- |
902+ nubBy :: forall a . (a -> a -> Ordering ) -> Array a -> Array a
903+ nubBy comp xs = case head indexedAndSorted of
904+ Nothing -> []
905+ Just x -> map snd $ sortWith fst $ ST .run do
906+ -- TODO: use NonEmptyArrays here to avoid partial functions
907+ result <- STA .unsafeThaw $ singleton x
908+ ST .foreach indexedAndSorted \pair@(Tuple i x') -> do
909+ lst <- snd <<< unsafePartial (fromJust <<< last) <$> STA .unsafeFreeze result
910+ when (comp lst x' /= EQ ) $ void $ STA .push pair result
911+ STA .unsafeFreeze result
912+ where
913+ indexedAndSorted :: Array (Tuple Int a )
914+ indexedAndSorted = sortBy (\x y -> comp (snd x) (snd y))
915+ (mapWithIndex Tuple xs)
878916
879917-- | Remove the duplicates from an array, where element equality is determined
880918-- | by the specified equivalence relation, creating a new array.
881919-- |
920+ -- | This less efficient version of `nubBy` only requires an equivalence
921+ -- | relation.
922+ -- |
882923-- | ```purescript
883- -- | nubBy (\a b -> a `mod` 3 == b `mod` 3) [1, 3, 4, 5, 6] = [1,3,5]
924+ -- | nubByEq (\a b -> a `mod` 3 == b `mod` 3) [1, 3, 4, 5, 6] = [1,3,5]
884925-- | ```
885926-- |
886- nubBy :: forall a . (a -> a -> Boolean ) -> Array a -> Array a
887- nubBy eq xs =
927+ nubByEq :: forall a . (a -> a -> Boolean ) -> Array a -> Array a
928+ nubByEq eq xs =
888929 case uncons xs of
889- Just o -> o.head : nubBy eq (filter (\y -> not (o.head `eq` y)) o.tail)
930+ Just o -> o.head : nubByEq eq (filter (\y -> not (o.head `eq` y)) o.tail)
890931 Nothing -> []
891932
892933-- | Calculate the union of two arrays. Note that duplicates in the first array
@@ -911,7 +952,7 @@ union = unionBy (==)
911952-- | ```
912953-- |
913954unionBy :: forall a . (a -> a -> Boolean ) -> Array a -> Array a -> Array a
914- unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubBy eq ys) xs
955+ unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubByEq eq ys) xs
915956
916957-- | Delete the first element of an array which is equal to the specified value,
917958-- | creating a new array.
@@ -1016,7 +1057,7 @@ zipWithA f xs ys = sequence (zipWith f xs ys)
10161057-- | discarded.
10171058-- |
10181059-- | ```purescript
1019- -- | zip [1, 2, 3] ["a", "b"] = [Tuple 1 "a", Tuple 2 "b"]
1060+ -- | zip [1, 2, 3] ["a", "b"] = [Tuple 1 "a", Tuple 2 "b"]
10201061-- | ```
10211062-- |
10221063zip :: forall a b . Array a -> Array b -> Array (Tuple a b )
@@ -1031,15 +1072,15 @@ zip = zipWith Tuple
10311072-- |
10321073unzip :: forall a b . Array (Tuple a b ) -> Tuple (Array a ) (Array b )
10331074unzip xs =
1034- pureST do
1035- fsts <- emptySTArray
1036- snds <- emptySTArray
1037- iter <- iterator (xs !! _)
1038- iterate iter \(Tuple fst snd) -> do
1039- void $ pushSTArray fsts fst
1040- void $ pushSTArray snds snd
1041- fsts' <- unsafeFreeze fsts
1042- snds' <- unsafeFreeze snds
1075+ ST .run do
1076+ fsts <- STA .empty
1077+ snds <- STA .empty
1078+ iter <- STAI . iterator (xs !! _)
1079+ STAI . iterate iter \(Tuple fst snd) -> do
1080+ void $ STA .push fst fsts
1081+ void $ STA .push snd snds
1082+ fsts' <- STA . unsafeFreeze fsts
1083+ snds' <- STA . unsafeFreeze snds
10431084 pure $ Tuple fsts' snds'
10441085
10451086-- | Perform a fold using a monadic step function.
@@ -1065,12 +1106,12 @@ foldRecM f a array = tailRecM2 go a 0
10651106-- | ```purescript
10661107-- | unsafePartial $ unsafeIndex ["a", "b", "c"] 1 = "b"
10671108-- | ```
1068- -- |
1069- -- | Using `unsafeIndex` with an out-of-range index will not immediately raise a runtime error.
1070- -- | Instead, the result will be undefined. Most attempts to subsequently use the result will
1071- -- | cause a runtime error, of course, but this is not guaranteed, and is dependent on the backend;
1072- -- | some programs will continue to run as if nothing is wrong. For example, in the JavaScript backend,
1073- -- | the expression `unsafePartial (unsafeIndex [true] 1)` has type `Boolean`;
1109+ -- |
1110+ -- | Using `unsafeIndex` with an out-of-range index will not immediately raise a runtime error.
1111+ -- | Instead, the result will be undefined. Most attempts to subsequently use the result will
1112+ -- | cause a runtime error, of course, but this is not guaranteed, and is dependent on the backend;
1113+ -- | some programs will continue to run as if nothing is wrong. For example, in the JavaScript backend,
1114+ -- | the expression `unsafePartial (unsafeIndex [true] 1)` has type `Boolean`;
10741115-- | since this expression evaluates to `undefined`, attempting to use it in an `if` statement will cause
10751116-- | the else branch to be taken.
10761117unsafeIndex :: forall a . Partial => Array a -> Int -> a
0 commit comments