10

What's a good way to convert List (Maybe a) to Maybe (List a) in Elm?

The logic is simple:

  • return Just (List a) if all items are Just a
  • otherwise, return Nothing.
Example 1:

input:  [ Just 1, Just 2, Just 3 ]
output: Just [ 1, 2, 3 ]

Example 2:

input:  [ Just 1, Nothing, Just 3 ]
output: Nothing

Can it be done easily with some of the built-in functions?

The best I came up with looks like this:

listOfMaybesToMaybeList : List (Maybe a) -> Maybe (List a)
listOfMaybesToMaybeList listOfMaybes =
    List.foldl
        (\maybeItem ->
            \maybeResultList ->
                case ( maybeItem, maybeResultList ) of
                    ( Just item, Just resultList ) ->
                        Just (List.append resultList [ item ])

                    ( _, _ ) ->
                        Nothing
        )
        (Just [])
        listOfMaybes

And what would be an appropriate name for this kind of function? As I was searching for an answer, I saw that there's a function called sequence in Haskell which seems to be doing something similar.

glennsl
  • 28,186
  • 12
  • 57
  • 75
Alex
  • 1,574
  • 17
  • 36
  • Whoever downvoted this could at least explain why the downvote. Otherwise I’ll never learn my mistake. – Alex Oct 28 '18 at 19:41
  • Sure, it's too broad because it asks multiple vague questions, partly opinion-based and fits much better in [codereview.se]. See [ask] and [help/on-topic] for more. – glennsl Oct 29 '18 at 08:31
  • I see your point, however I’m not sure it fits much better in code review, because I don’t want anyone to review my code. But I do see that if you thought so, there’s probably some fault in the way I expressed myself. – Alex Oct 29 '18 at 10:11

2 Answers2

8

You can use the Elm Fancy Search tool and search on the function signature: List (Maybe a) -> Maybe (List a)

The first result turns up Maybe.Extra.combine

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
6

@Chad Gilbert's answer sure is correct, but if you're looking for a simpler implementation of such a function, then the following line will do the trick:

listOfMaybesToMaybeList : List (Maybe a) -> Maybe (List a)
listOfMaybesToMaybeList listOfMaybes =
    List.foldr (Maybe.map2 (::)) (Just []) listOfMaybes

Or just:

listOfMaybesToMaybeList : List (Maybe a) -> Maybe (List a)
listOfMaybesToMaybeList = List.foldr (Maybe.map2 (::)) (Just [])

Maybe.map2 just takes a function and two Maybe values and applies the function to the values:

> Maybe.map2 (+) (Just 2) (Just 3)
Just 5 : Maybe.Maybe number
> Maybe.map2 (::) (Just 2) (Just [1])
Just [2,1] : Maybe.Maybe (List number)

Note, that (::) function (prepend to the list) is used instead of (++) or List.append because it's more performant for the lists. Then foldr must be used instead of foldl to retain the order.

Igor Drozdov
  • 14,690
  • 5
  • 37
  • 53
  • Thanks, I didn’t know about the performance difference. And nice use of built-in functions! – Alex Oct 29 '18 at 10:10