From 03e3105e700ff087976b9d7946026e3e93e13e00 Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:22:37 +0200 Subject: [PATCH 1/6] add `firstJustMap`, `allJustMap` --- src/Array/Extra.elm | 96 +++++++++++++++++++++++++++++++++++++++++++-- tests/Tests.elm | 38 ++++++++++++++++++ 2 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index b93a061..85b4e39 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -1,8 +1,8 @@ module Array.Extra exposing - ( all, any, member + ( all, any, firstJustMap, member , reverse, intersperse , update, pop, removeAt, insertAt - , removeWhen, filterMap + , removeWhen, filterMap, allJustMap , sliceFrom, sliceUntil, splitAt, unzip , interweave, apply, map2, map3, map4, map5, zip, zip3 , resizelRepeat, resizerRepeat, resizelIndexed, resizerIndexed @@ -14,7 +14,7 @@ module Array.Extra exposing # observe -@docs all, any, member +@docs all, any, firstJustMap, member # alter @@ -25,7 +25,7 @@ module Array.Extra exposing ## filter -@docs removeWhen, filterMap +@docs removeWhen, filterMap, allJustMap ## part @@ -195,6 +195,94 @@ consTry maybeNewHead = list +{-| After applying the given function to every element, +try unpacking _all_ `Just` values. +If just a single element is `Nothing`, `Nothing` is returned. + + import Array exposing (empty, fromList) + + empty + |> allJustMap String.toInt + --> Just empty + + fromList [ "1", "2", "3" ] + |> allJustMap String.toInt + --> Just (fromList [ 1, 2, 3 ]) + + fromList [ "1", "NaN", "3" ] + |> allJustMap String.toInt + --> Nothing + +This is often called "traverse". +A version with óut the map is often called "sequence" +and `Maybe.Extra` calls it [`combineArray`](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra#combineArray) + +-} +allJustMap : + (element -> Maybe narrowElement) + -> Array element + -> Maybe (Array narrowElement) +allJustMap elementToMaybeValue = + \array -> + array + |> Array.foldr + (\element soFar -> + case soFar of + Nothing -> + Nothing + + Just soFarList -> + Maybe.map + (\value -> soFarList |> (::) value) + (element |> elementToMaybeValue) + ) + ([] |> Just) + |> Maybe.map Array.fromList + + +{-| The first element (the one with lowest index) that returns a `Just` value for a given function. +If every element is transformed to `Nothing`, `Nothing` is returned. + +This is like a nicer [`any`](#any) where if you test for certain elements you already get one +that matches your search. + + import Array exposing (empty, fromList) + + empty + |> firstJustMap String.toInt + --> Nothing + + fromList [ "1", "2", "3" ] + |> firstJustMap String.toInt + --> Just 1 + + fromList [ "NaN", "2", "3" ] + |> firstJustMap String.toInt + --> Just 2 + +This is often called "findMap", +`Maybe.Extra` calls it [`combineArray`](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra#combineArray) + +-} +firstJustMap : + (element -> Maybe narrowElement) + -> Array element + -> Maybe narrowElement +firstJustMap elementToMaybeValue = + \array -> + array + |> Array.foldl + (\element soFar -> + case soFar of + Just found -> + found |> Just + + Nothing -> + element |> elementToMaybeValue + ) + Nothing + + {-| Apply a given `Array` of changes to all elements. If one `Array` is longer, its extra elements are not used. diff --git a/tests/Tests.elm b/tests/Tests.elm index ecf9822..dbb6061 100644 --- a/tests/Tests.elm +++ b/tests/Tests.elm @@ -889,6 +889,44 @@ suite = ) ) ] + , Test.describe "firstJustMap" + [ Test.fuzz (Fuzz.array (Fuzz.maybe Fuzz.int)) + "is equivalent to filterMap |> get 0" + (\maybes -> + maybes + |> Array.firstJustMap identity + |> Expect.equal + (maybes + |> Array.filterMap identity + |> Array.get 0 + ) + ) + ] + , Test.describe "allJustMap" + [ Test.fuzz (Fuzz.array (Fuzz.map Just Fuzz.int)) + "is equivalent to Just filterMap when only justs" + (\maybes -> + maybes + |> Array.allJustMap identity + |> Expect.equal + (maybes + |> Array.filterMap identity + |> Just + ) + ) + , Test.fuzz + (Fuzz.constant (\before after -> Array.append (before |> Array.push Nothing) after) + |> Fuzz.andMap (Fuzz.array (Fuzz.maybe Fuzz.int)) + |> Fuzz.andMap (Fuzz.array (Fuzz.maybe Fuzz.int)) + ) + "is equivalent to Nothing when one Nothing" + (\maybes -> + maybes + |> Array.allJustMap identity + |> Expect.equal + Nothing + ) + ] ] From 2f5eb7bda54621f9ca1dea7c6f762a4f7f14d0df Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:35:10 +0200 Subject: [PATCH 2/6] `allJustMap` point out similarities to `all` --- src/Array/Extra.elm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index 85b4e39..41a83b7 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -199,6 +199,9 @@ consTry maybeNewHead = try unpacking _all_ `Just` values. If just a single element is `Nothing`, `Nothing` is returned. +This is like a nicer [`all`](#all) where if you test for certain elements you already get +the `Array` with all the successful results or `Nothing` if one wasn't successful. + import Array exposing (empty, fromList) empty From 5439440571d687a37febd005776e0da7049dd93b Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:46:05 +0200 Subject: [PATCH 3/6] reformat `consTry` --- src/Array/Extra.elm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index 41a83b7..57f2e17 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -186,13 +186,12 @@ filterMap tryMap = consTry : Maybe a -> List a -> List a consTry maybeNewHead = - \list -> - case maybeNewHead of - Just newHead -> - newHead :: list + case maybeNewHead of + Just newHead -> + \list -> list |> (::) newHead - Nothing -> - list + Nothing -> + identity {-| After applying the given function to every element, From 00f21e1f12a95f39f0f990ef258ae08b8699b864 Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:46:30 +0200 Subject: [PATCH 4/6] correct other names for `firstJustMap` --- src/Array/Extra.elm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index 57f2e17..c19a89a 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -262,8 +262,8 @@ that matches your search. |> firstJustMap String.toInt --> Just 2 -This is often called "findMap", -`Maybe.Extra` calls it [`combineArray`](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra#combineArray) +This is often called "findMap" +(for example in [`List.Extra`](https://package.elm-lang.org/packages/elm-community/list-extra/latest/List-Extra#findMap)). -} firstJustMap : From 7ad8c08880fe8aad7444e7d07e89837f757eb19f Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:47:28 +0200 Subject: [PATCH 5/6] don't write out `combine-Array` --- src/Array/Extra.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index c19a89a..710fae7 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -217,7 +217,7 @@ the `Array` with all the successful results or `Nothing` if one wasn't successfu This is often called "traverse". A version with óut the map is often called "sequence" -and `Maybe.Extra` calls it [`combineArray`](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra#combineArray) +and `Maybe.Extra` calls it [`combine`](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra#combineArray) -} allJustMap : From de0edbbfe90ed4dce0a7b9375600e5c0cac596de Mon Sep 17 00:00:00 2001 From: lue-bird Date: Mon, 5 Jun 2023 11:48:48 +0200 Subject: [PATCH 6/6] =?UTF-8?q?rename=20`consTry`=20=E2=86=92=20`consJust`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Array/Extra.elm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Array/Extra.elm b/src/Array/Extra.elm index 710fae7..9062422 100644 --- a/src/Array/Extra.elm +++ b/src/Array/Extra.elm @@ -179,13 +179,13 @@ filterMap tryMap = \array -> array |> Array.foldr - (\el soFar -> soFar |> consTry (el |> tryMap)) + (\el soFar -> soFar |> consJust (el |> tryMap)) [] |> Array.fromList -consTry : Maybe a -> List a -> List a -consTry maybeNewHead = +consJust : Maybe a -> List a -> List a +consJust maybeNewHead = case maybeNewHead of Just newHead -> \list -> list |> (::) newHead