tanman
tanman

Reputation: 1389

Is there a less verbose way to unwrap maybe values in Elm

I've been running into a frequent issue in elm where I have a function that depends on multiple maybe values being Just. Is there a less verbose way to write this code:

commandIf apples bananas oranges =
        case apples of
            Just apples_ ->
                case bananas of
                    Just bananas_ ->
                        case oranges of
                            Just oranges_ ->
                                someCommand apples_ bananas_ oranges_

                            Nothing ->
                                Cmd.none

                    Nothing ->
                        Cmd.none

            Nothing ->
                Cmd.none

Upvotes: 10

Views: 1936

Answers (3)

Sridhar Ratnakumar
Sridhar Ratnakumar

Reputation: 85442

Maybe.map3 solves your particular case, but this answer is about the general pattern of chaining maybe values using Maybe.andThen.

commandIf a_ b_ c_ =
  a_ |> Maybe.andThen (\a ->
    b_ |> Maybe.andThen (\b ->
      c_ |> Maybe.andThen (Just << someCommand a b)))
  |> Maybe.withDefault Cmd.none

Upvotes: 1

wintvelt
wintvelt

Reputation: 14101

@laughedelic's answer is very good. Just wanted to offer some alternative and more generic solutions too, since verbose Maybe unwrapping is an issue I also ran into when I started out in Elm.

If you have a fixed number of Maybe values, you can use map2, map3 etc to do what you want (docs here):

commandIf apples bananas oranges =
  Maybe.map3 someCommand apples bananas oranges
  |> Maybe.withDefault Cmd.none

Here, someCommand is your functions that takes 3 arguments, and returns a some command.

Maybe.map3 applies this function only if all 3 variables are Just x, and wraps it in one Maybe type. So the result is Just (someCommand apples bananas oranges) if all 3 have a value. Otherwise, the function returns Nothing.

This result is then "piped" into Maybe.withDefault. Which returns a Cmd.none if the input is Nothing, and otherwise returns the value (your command), without the Just.

If you would have a list of Maybe values of unknown length, you could do something this:

keepOnlyJusts : List (Maybe a) -> List a
keepOnlyJusts listOfMaybes =
  listOfMaybes
  |> List.filterMap identity

newList = keepOnlyJusts [ Just 1, Nothing, Just 3 ]   -- == [1,3]

where the result is a list (could be empty) where only the values are kept.

Upvotes: 11

laughedelic
laughedelic

Reputation: 6460

If you need all three values at the same time you can match them together as a tuple and leave all other combinations (when one of them or several are Nothing) to the fallback case:

commandIf apples bananas oranges =
  case (apples, bananas, oranges) of
    (Just apples_, Just bananas_, Just oranges_) ->
        someCommand apples_ bananas_ oranges_

    _ ->
        Cmd.none

Upvotes: 12

Related Questions