ianmjones
ianmjones

Reputation: 3415

How do I use a Maybe (List a) in a map?

I have a weird situation that I just can't figure out.

type alias Schedule =
    { name : String
    , display : String
    , interval : Maybe Int
    , events : Maybe (List Event)
    }


type alias Event =
    { schedule : Maybe String
    , interval : Maybe Int
    , hook : String
    , args : List ( String, String )
    , timestamp : Int
    , seconds_due : Int
    }

setScheduledEventDueNow : Event -> Schedule -> Schedule
setScheduledEventDueNow event schedule =
    case schedule.events of
        Just events ->
            { schedule | events = List.map (setMatchedEventDueNow event) events }

        Nothing ->
            schedule

There may or may not be a List of Events in the Schedule, so it's set as events : Maybe (List Event).

In response to an action on a known Event I want to run through the events on a schedule if it has any, and potentially return an updated list of events for the schedule.

However, I'm getting the following error:

-- TYPE MISMATCH ----------------------------------------- src/elm/CronPixie.elm

The 1st and 2nd branches of this `case` produce different types of values.

373|     case schedule.events of
374|         Just events ->
375|             { schedule | events = List.map (setMatchedEventDueNow event) events }
376| 
377|         Nothing ->
378|>            schedule

The 1st branch has this type:

    { a | events : List Event }

But the 2nd is:

    { a | events : Maybe (List Event) }

Hint: All branches in a `case` must have the same type. So no matter which one
we take, we always get back the same type of value.

Detected errors in 1 module.

My beginner brain thought because I had verified that there really was a list of events with the case statement, that all should be good to map it.

But the compiler is recognising that it's a simple List.map with no chance of a Maybe, so naturally complains about the difference between what is returned by the two branches of the case.

Any idea how I get around this?

Upvotes: 0

Views: 731

Answers (1)

Chad Gilbert
Chad Gilbert

Reputation: 36385

You need to wrap the list using Just

Just events ->
    { schedule | events = Just <| List.map (setMatchedEventDueNow event) events }

You could write the whole function more succinctly by using Maybe.map, which returns Nothing if the list of events is already Nothing, and maps to the underlying list using the provided function otherwise:

setScheduledEventDueNow : Event -> Schedule -> Schedule
setScheduledEventDueNow event schedule =
  { schedule | events = Maybe.map (List.map <| setMatchedEventDueNow event) schedule.events }

Upvotes: 2

Related Questions