Skip to content

Commit 845fb13

Browse files
authored
Merge pull request #77 from purescript/remove-uncons
Remove a couple of uses of uncons
2 parents 3159f7e + 58fa234 commit 845fb13

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

src/Data/Array.purs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,12 @@ import Partial.Unsafe (unsafePartial)
128128

129129
-- | Convert an `Array` into an `Unfoldable` structure.
130130
toUnfoldable :: forall f a. Unfoldable f => Array a -> f a
131-
toUnfoldable = unfoldr $ uncons' (const Nothing) (\h t -> Just (Tuple h t))
131+
toUnfoldable xs = unfoldr f 0
132+
where
133+
len = length xs
134+
f i
135+
| i < len = Just (Tuple (unsafePartial (unsafeIndex xs i)) (i+1))
136+
| otherwise = Nothing
132137

133138
-- | Convert a `Foldable` structure into an `Array`.
134139
fromFoldable :: forall f a. Foldable f => f a -> Array a
@@ -219,7 +224,7 @@ insertBy cmp x ys =
219224
-- |
220225
-- | Running time: `O(1)`.
221226
head :: forall a. Array a -> Maybe a
222-
head = uncons' (const Nothing) (\x _ -> Just x)
227+
head xs = xs !! 0
223228

224229
-- | Get the last element in an array, or `Nothing` if the array is empty
225230
-- |
@@ -481,25 +486,37 @@ dropWhile p xs = (span p xs).rest
481486

482487
-- | Split an array into two parts:
483488
-- |
484-
-- | 1. the longest initial subarray for which all element satisfy the specified
485-
-- | predicate
489+
-- | 1. the longest initial subarray for which all elements satisfy the
490+
-- | specified predicate
486491
-- | 2. the remaining elements
487492
-- |
488493
-- | ```purescript
489494
-- | span (\n -> n % 2 == 1) [1,3,2,4,5] == { init: [1,3], rest: [2,4,5] }
490495
-- | ```
496+
-- |
497+
-- | Running time: `O(n)`.
491498
span
492499
:: forall a
493500
. (a -> Boolean)
494501
-> Array a
495502
-> { init :: Array a, rest :: Array a }
496-
span p = go []
503+
span p arr =
504+
case breakIndex of
505+
Just 0 ->
506+
{ init: [], rest: arr }
507+
Just i ->
508+
{ init: slice 0 i arr, rest: slice i (length arr) arr }
509+
Nothing ->
510+
{ init: arr, rest: [] }
497511
where
498-
go :: Array a -> Array a -> { init :: Array a, rest :: Array a }
499-
go acc xs =
500-
case uncons xs of
501-
Just { head: x, tail: xs' } | p x -> go (x : acc) xs'
502-
_ -> { init: reverse acc, rest: xs }
512+
breakIndex = go 0
513+
go i =
514+
-- This looks like a good opportunity to use the Monad Maybe instance,
515+
-- but it's important to write out an explicit case expression here in
516+
-- order to ensure that TCO is triggered.
517+
case index arr i of
518+
Just x -> if p x then go (i+1) else Just i
519+
Nothing -> Nothing
503520

504521
-- | Group equal, consecutive elements of an array into arrays.
505522
-- |

test/Test/Data/Array.purs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import Prelude
55
import Control.Monad.Eff (Eff)
66
import Control.Monad.Eff.Console (log, CONSOLE)
77

8-
import Data.Array (range, replicate, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group', group, span, dropWhile, drop, takeWhile, take, sortBy, sort, catMaybes, mapMaybe, mapWithIndex, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, init, tail, last, head, insertBy, insert, snoc, (:), length, null, singleton, fromFoldable)
9-
import Data.Foldable (for_, foldMapDefaultR, class Foldable, all)
8+
import Data.Array (range, replicate, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group', group, span, dropWhile, drop, takeWhile, take, sortBy, sort, catMaybes, mapMaybe, mapWithIndex, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, init, tail, last, head, insertBy, insert, snoc, (:), length, null, singleton, fromFoldable, toUnfoldable)
9+
import Data.Foldable (for_, foldMapDefaultR, class Foldable, all, traverse_)
1010
import Data.Maybe (Maybe(..), isNothing, fromJust)
1111
import Data.NonEmpty ((:|))
1212
import Data.NonEmpty as NE
@@ -237,9 +237,30 @@ testArray = do
237237
assert $ (drop (-2) [1, 2, 3]) == [1, 2, 3]
238238

239239
log "span should split an array in two based on a predicate"
240-
let spanResult = span (_ < 4) [1, 2, 3, 4, 5, 6, 7]
241-
assert $ spanResult.init == [1, 2, 3]
242-
assert $ spanResult.rest == [4, 5, 6, 7]
240+
let testSpan { p, input, init_, rest_ } = do
241+
let result = span p input
242+
assert $ result.init == init_
243+
assert $ result.rest == rest_
244+
245+
let oneToSeven = [1, 2, 3, 4, 5, 6, 7]
246+
testSpan { p: (_ < 4), input: oneToSeven, init_: [1, 2, 3], rest_: [4, 5, 6, 7] }
247+
248+
log "span with all elements satisfying the predicate"
249+
testSpan { p: const true, input: oneToSeven, init_: oneToSeven, rest_: [] }
250+
251+
log "span with no elements satisfying the predicate"
252+
testSpan { p: const false, input: oneToSeven, init_: [], rest_: oneToSeven }
253+
254+
log "span with large inputs: 10000"
255+
let testBigSpan n =
256+
testSpan { p: (_ < n), input: range 1 n, init_: range 1 (n-1), rest_: [n] }
257+
testBigSpan 10000
258+
259+
log "span with large inputs: 40000"
260+
testBigSpan 40000
261+
262+
log "span with large inputs: 100000"
263+
testBigSpan 100000
243264

244265
log "group should group consecutive equal elements into arrays"
245266
assert $ group [1, 2, 2, 3, 3, 3, 1] == [NE.singleton 1, 2 :| [2], 3:| [3, 3], NE.singleton 1]
@@ -308,6 +329,17 @@ testArray = do
308329
assert $ length arr == n
309330
assert $ all (_ == elem) arr
310331

332+
log "toUnfoldable"
333+
let toUnfoldableId xs = toUnfoldable xs == xs
334+
traverse_ (assert <<< toUnfoldableId)
335+
[ []
336+
, [1]
337+
, [1,2,3]
338+
, [2,3,1]
339+
, [4,0,0,1,25,36,458,5842,23757]
340+
]
341+
342+
311343
nil :: Array Int
312344
nil = []
313345

0 commit comments

Comments
 (0)