Skip to content

Commit e5059a4

Browse files
committed
NonEmptyArray: Unfoldable1 support
ported by hand from #138
1 parent 01a9175 commit e5059a4

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

src/Data/Array/NonEmpty.purs

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Data.Array.NonEmpty
88
, fromFoldable
99
, fromFoldable1
1010
, toUnfoldable
11+
, toUnfoldable1
1112
, singleton
1213
, (..), range
1314
, replicate
@@ -105,8 +106,9 @@ import Data.Foldable (class Foldable)
105106
import Data.Maybe (Maybe(..), fromJust)
106107
import Data.NonEmpty (NonEmpty, (:|))
107108
import Data.Semigroup.Foldable (class Foldable1)
108-
import Data.Tuple (Tuple)
109+
import Data.Tuple (Tuple(..))
109110
import Data.Unfoldable (class Unfoldable)
111+
import Data.Unfoldable1 (class Unfoldable1, unfoldr1)
110112
import Partial.Unsafe (unsafePartial)
111113
import Unsafe.Coerce (unsafeCoerce)
112114

@@ -159,6 +161,13 @@ fromFoldable1 = unsafeFromArray <<< A.fromFoldable
159161
toUnfoldable :: forall f a. Unfoldable f => NonEmptyArray a -> f a
160162
toUnfoldable = adaptAny A.toUnfoldable
161163

164+
toUnfoldable1 :: forall f a. Unfoldable1 f => NonEmptyArray a -> f a
165+
toUnfoldable1 xs = unfoldr1 f 0
166+
where
167+
len = length xs
168+
f i = Tuple (unsafePartial unsafeIndex xs i) $
169+
if i < (len - 1) then Just (i + 1) else Nothing
170+
162171
singleton :: forall a. a -> NonEmptyArray a
163172
singleton = unsafeFromArray <<< A.singleton
164173

src/Data/Array/NonEmpty/Internal.js

+21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ exports.fold1Impl = function (f) {
1111
};
1212
};
1313

14+
exports.unfoldr1Impl = function (isNothing) {
15+
return function (fromJust) {
16+
return function (fst) {
17+
return function (snd) {
18+
return function (f) {
19+
return function (value) {
20+
var result = [];
21+
while (true) { // eslint-disable-line no-constant-condition
22+
var tuple = f(value);
23+
result.push(fst(tuple));
24+
var maybe = snd(tuple);
25+
if (isNothing(maybe)) return result;
26+
value = fromJust(maybe); // eslint-disable-line no-param-reassign
27+
}
28+
};
29+
};
30+
};
31+
};
32+
};
33+
};
34+
1435
exports.traverse1Impl = function () {
1536
function Cont(fn) {
1637
this.fn = fn;

src/Data/Array/NonEmpty/Internal.purs

+21-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@ import Data.Eq (class Eq1)
77
import Data.Foldable (class Foldable)
88
import Data.FoldableWithIndex (class FoldableWithIndex)
99
import Data.FunctorWithIndex (class FunctorWithIndex)
10+
import Data.Maybe (Maybe, fromJust, isNothing)
1011
import Data.Ord (class Ord1)
1112
import Data.Semigroup.Foldable (class Foldable1, foldMap1Default)
1213
import Data.Semigroup.Traversable (class Traversable1, sequence1Default)
1314
import Data.Traversable (class Traversable)
1415
import Data.TraversableWithIndex (class TraversableWithIndex)
16+
import Data.Tuple (Tuple, fst, snd)
17+
import Data.Unfoldable1 (class Unfoldable1)
18+
import Partial.Unsafe (unsafePartial)
1519

1620
newtype NonEmptyArray a = NonEmptyArray (Array a)
1721

@@ -24,6 +28,8 @@ derive newtype instance eq1NonEmptyArray :: Eq1 NonEmptyArray
2428
derive newtype instance ordNonEmptyArray :: Ord a => Ord (NonEmptyArray a)
2529
derive newtype instance ord1NonEmptyArray :: Ord1 NonEmptyArray
2630

31+
derive newtype instance semigroupNonEmptyArray :: Semigroup (NonEmptyArray a)
32+
2733
derive newtype instance functorNonEmptyArray :: Functor NonEmptyArray
2834
derive newtype instance functorWithIndexNonEmptyArray :: FunctorWithIndex Int NonEmptyArray
2935

@@ -34,10 +40,13 @@ instance foldable1NonEmptyArray :: Foldable1 NonEmptyArray where
3440
foldMap1 = foldMap1Default
3541
fold1 = fold1Impl (<>)
3642

43+
instance unfoldable1NonEmptyArray :: Unfoldable1 NonEmptyArray where
44+
unfoldr1 = unfoldr1Impl isNothing (unsafePartial fromJust) fst snd
45+
3746
derive newtype instance traversableNonEmptyArray :: Traversable NonEmptyArray
3847
derive newtype instance traversableWithIndexNonEmptyArray :: TraversableWithIndex Int NonEmptyArray
3948

40-
instance traversable1NonEmptyArray :: Traversable1 NonEmptyArray where
49+
instance traversable1NonEmptyArray :: Traversable1 NonEmptyArray where
4150
traverse1 = traverse1Impl apply map
4251
sequence1 = sequence1Default
4352

@@ -51,9 +60,19 @@ derive newtype instance monadNonEmptyArray :: Monad NonEmptyArray
5160

5261
derive newtype instance altNonEmptyArray :: Alt NonEmptyArray
5362

54-
-- we use FFI here to avoid the unnecessary copy created by `tail`
63+
-- we use FFI here to avoid the unncessary copy created by `tail`
5564
foreign import fold1Impl :: forall a. (a -> a -> a) -> NonEmptyArray a -> a
5665

66+
foreign import unfoldr1Impl
67+
:: forall a b
68+
. (forall x. Maybe x -> Boolean)
69+
-> (forall x. Maybe x -> x)
70+
-> (forall x y. Tuple x y -> x)
71+
-> (forall x y. Tuple x y -> y)
72+
-> (b -> Tuple a (Maybe b))
73+
-> b
74+
-> NonEmptyArray a
75+
5776
foreign import traverse1Impl
5877
:: forall m a b
5978
. (forall a' b'. (m (a' -> b') -> m a' -> m b'))

test/Test/Data/Array/NonEmpty.purs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@ module Test.Data.Array.NonEmpty (testNonEmptyArray) where
22

33
import Prelude
44

5+
import Data.Array as A
56
import Data.Array.NonEmpty as NEA
67
import Data.Const (Const(..))
78
import Data.Foldable (for_, sum, traverse_)
89
import Data.FunctorWithIndex (mapWithIndex)
910
import Data.Maybe (Maybe(..), fromJust)
1011
import Data.Monoid.Additive (Additive(..))
12+
import Data.NonEmpty ((:|))
1113
import Data.Semigroup.Foldable (foldMap1)
1214
import Data.Semigroup.Traversable (traverse1)
1315
import Data.Tuple (Tuple(..))
16+
import Data.Unfoldable1 as U1
1417
import Effect (Effect)
15-
import Effect.Console (log, logShow)
18+
import Effect.Console (log)
1619
import Partial.Unsafe (unsafePartial)
1720
import Test.Assert (assert)
1821

@@ -288,6 +291,12 @@ testNonEmptyArray = do
288291
, fromArray [4,0,0,1,25,36,458,5842,23757]
289292
])
290293

294+
log "toUnfoldable1"
295+
assert $ NEA.toUnfoldable1 (NEA.range 0 9) == 0 :| A.range 1 9
296+
297+
log "Unfoldable instance"
298+
assert $ U1.range 0 9 == NEA.range 0 9
299+
291300
log "foldl should work"
292301
-- test through sum
293302
assert $ sum (fromArray [1, 2, 3, 4]) == 10

0 commit comments

Comments
 (0)