25
25
-- | `Data.Foldable.or` tests whether an array of `Boolean` values contains
26
26
-- | at least one `true` value.
27
27
-- | * `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.
29
29
-- |
30
30
module Data.Array
31
31
( fromFoldable
@@ -90,7 +90,9 @@ module Data.Array
90
90
, groupBy
91
91
92
92
, nub
93
+ , nubEq
93
94
, nubBy
95
+ , nubByEq
94
96
, union
95
97
, unionBy
96
98
, delete
@@ -114,22 +116,24 @@ module Data.Array
114
116
) where
115
117
116
118
import Prelude
119
+
117
120
import Control.Alt ((<|>))
118
121
import Control.Alternative (class Alternative )
119
122
import Control.Lazy (class Lazy , defer )
120
123
import 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 )
124
128
import Data.Foldable (class Foldable , foldl , foldr , traverse_ )
125
129
import Data.Foldable (foldl , foldr , foldMap , fold , intercalate , elem , notElem , find , findMap , any , all ) as Exports
126
130
import Data.Maybe (Maybe (..), maybe , isJust , fromJust )
127
- import Data.NonEmpty (NonEmpty , (:|))
128
131
import Data.Traversable (scanl , scanr ) as Exports
129
132
import Data.Traversable (sequence , traverse )
130
- import Data.Tuple (Tuple (..), uncurry )
133
+ import Data.Tuple (Tuple (..), fst , snd )
131
134
import Data.Unfoldable (class Unfoldable , unfoldr )
132
135
import Partial.Unsafe (unsafePartial )
136
+ import Unsafe.Coerce (unsafeCoerce )
133
137
134
138
-- | Convert an `Array` into an `Unfoldable` structure.
135
139
toUnfoldable :: forall f . Unfoldable f => Array ~> f
@@ -299,7 +303,7 @@ last xs = xs !! (length xs - 1)
299
303
-- | `Nothing` if the array is empty
300
304
-- |
301
305
-- | ```purescript
302
- -- | tail [1, 2, 3, 4] = Just [2, 3, 4]
306
+ -- | tail [1, 2, 3, 4] = Just [2, 3, 4]
303
307
-- | tail [] = Nothing
304
308
-- | ```
305
309
-- |
@@ -348,7 +352,7 @@ foreign import uncons'
348
352
-- | Break an array into its last element and all preceding elements.
349
353
-- |
350
354
-- | ```purescript
351
- -- | unsnoc [1, 2, 3] = Just {init: [1, 2], last: 3}
355
+ -- | unsnoc [1, 2, 3] = Just {init: [1, 2], last: 3}
352
356
-- | unsnoc [] = Nothing
353
357
-- | ```
354
358
-- |
@@ -511,7 +515,7 @@ foreign import _updateAt
511
515
-- | array, or returning `Nothing` if the index is out of bounds.
512
516
-- |
513
517
-- | ```purescript
514
- -- | modifyAt 1 toUpper ["Hello", "World"] = Just ["Hello", "WORLD"]
518
+ -- | modifyAt 1 toUpper ["Hello", "World"] = Just ["Hello", "WORLD"]
515
519
-- | modifyAt 10 toUpper ["Hello", "World"] = Nothing
516
520
-- | ```
517
521
-- |
@@ -525,10 +529,10 @@ modifyAt i f xs = maybe Nothing go (xs !! i)
525
529
-- | index is out-of-bounds.
526
530
-- |
527
531
-- | ```purescript
528
- -- | alterAt 1 (stripSuffix $ Pattern "!") ["Hello", "World!"]
532
+ -- | alterAt 1 (stripSuffix $ Pattern "!") ["Hello", "World!"]
529
533
-- | = Just ["Hello", "World"]
530
534
-- |
531
- -- | alterAt 1 (stripSuffix $ Pattern "!!!!!") ["Hello", "World!"]
535
+ -- | alterAt 1 (stripSuffix $ Pattern "!!!!!") ["Hello", "World!"]
532
536
-- | = Just ["Hello"]
533
537
-- |
534
538
-- | alterAt 10 (stripSuffix $ Pattern "!") ["Hello", "World!"] = Nothing
@@ -629,7 +633,7 @@ mapMaybe f = concatMap (maybe [] singleton <<< f)
629
633
-- | ```
630
634
-- |
631
635
catMaybes :: forall a . Array (Maybe a ) -> Array a
632
- catMaybes = mapMaybe id
636
+ catMaybes = mapMaybe identity
633
637
634
638
-- | Apply a function to each element in an array, supplying a generated
635
639
-- | zero-based index integer along with the element, creating an array
@@ -656,7 +660,7 @@ mapWithIndex f xs =
656
660
-- |
657
661
updateAtIndices :: forall t a . Foldable t => t (Tuple Int a ) -> Array a -> Array a
658
662
updateAtIndices 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)
660
664
661
665
-- | Apply a function to the element at the specified indices,
662
666
-- | creating a new array. Out-of-bounds indices will have no effect.
@@ -669,7 +673,7 @@ updateAtIndices us xs =
669
673
-- |
670
674
modifyAtIndices :: forall t a . Foldable t => t Int -> (a -> a ) -> Array a -> Array a
671
675
modifyAtIndices 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)
673
677
674
678
-- ------------------------------------------------------------------------------
675
679
-- Sorting ---------------------------------------------------------------------
@@ -836,15 +840,15 @@ span p arr =
836
840
-- | ```purescript
837
841
-- | group [1,1,2,2,1] == [NonEmpty 1 [1], NonEmpty 2 [2], NonEmpty 1 []]
838
842
-- | ```
839
- group :: forall a . Eq a => Array a -> Array (NonEmpty Array a )
843
+ group :: forall a . Eq a => Array a -> Array (NonEmptyArray a )
840
844
group xs = groupBy eq xs
841
845
842
846
-- | Sort and then group the elements of an array into arrays.
843
847
-- |
844
848
-- | ```purescript
845
849
-- | group' [1,1,2,2,1] == [NonEmpty 1 [1,1],NonEmpty 2 [2]]
846
850
-- | ```
847
- group' :: forall a . Ord a => Array a -> Array (NonEmpty Array a )
851
+ group' :: forall a . Ord a => Array a -> Array (NonEmptyArray a )
848
852
group' = group <<< sort
849
853
850
854
-- | Group equal, consecutive elements of an array into arrays, using the
@@ -855,38 +859,75 @@ group' = group <<< sort
855
859
-- | = [NonEmpty 1 [3], NonEmpty 2 [] , NonEmpty 4 [], NonEmpty 3 [3]]
856
860
-- | ```
857
861
-- |
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 )
859
863
groupBy 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
869
874
870
875
-- | Remove the duplicates from an array, creating a new array.
871
876
-- |
872
877
-- | ```purescript
873
878
-- | nub [1, 2, 1, 3, 3] = [1, 2, 3]
874
879
-- | ```
875
880
-- |
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)
878
916
879
917
-- | Remove the duplicates from an array, where element equality is determined
880
918
-- | by the specified equivalence relation, creating a new array.
881
919
-- |
920
+ -- | This less efficient version of `nubBy` only requires an equivalence
921
+ -- | relation.
922
+ -- |
882
923
-- | ```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]
884
925
-- | ```
885
926
-- |
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 =
888
929
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)
890
931
Nothing -> []
891
932
892
933
-- | Calculate the union of two arrays. Note that duplicates in the first array
@@ -911,7 +952,7 @@ union = unionBy (==)
911
952
-- | ```
912
953
-- |
913
954
unionBy :: 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
915
956
916
957
-- | Delete the first element of an array which is equal to the specified value,
917
958
-- | creating a new array.
@@ -1016,7 +1057,7 @@ zipWithA f xs ys = sequence (zipWith f xs ys)
1016
1057
-- | discarded.
1017
1058
-- |
1018
1059
-- | ```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"]
1020
1061
-- | ```
1021
1062
-- |
1022
1063
zip :: forall a b . Array a -> Array b -> Array (Tuple a b )
@@ -1031,15 +1072,15 @@ zip = zipWith Tuple
1031
1072
-- |
1032
1073
unzip :: forall a b . Array (Tuple a b ) -> Tuple (Array a ) (Array b )
1033
1074
unzip 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
1043
1084
pure $ Tuple fsts' snds'
1044
1085
1045
1086
-- | Perform a fold using a monadic step function.
@@ -1065,12 +1106,12 @@ foldRecM f a array = tailRecM2 go a 0
1065
1106
-- | ```purescript
1066
1107
-- | unsafePartial $ unsafeIndex ["a", "b", "c"] 1 = "b"
1067
1108
-- | ```
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`;
1074
1115
-- | since this expression evaluates to `undefined`, attempting to use it in an `if` statement will cause
1075
1116
-- | the else branch to be taken.
1076
1117
unsafeIndex :: forall a . Partial => Array a -> Int -> a
0 commit comments