elmconscdr

Elm how to update head of list


I am trying to program small time tracking application, where I write what I do, and it just logs it.

I successfully implemented adding entries to log, but now, I want to update last log entry with duration (for example when I started programming at 00:01, now it is 00:20 and I starting to write question on SO, so when I add that log entry to list, I want head of the list to have duration of 19 minutes, so I know how much time I spent programming).

I try to do it with this code:

addEntry: Model -> List LogEntry
addEntry model =
    let
        newEntry = { -- this is what we add
            text = model.currentText,
            timestamp = model.now,
            duration = Nothing
        }
        lastEntry =
            List.head model.log
    in
       case lastEntry of
           Nothing ->
                [newEntry] -- when the list was empty - create it with one element
           Just le -> -- when not empty
                newEntry :: {le | duration = newEntry.timestamp - le.timestamp } :: List.tail model.log
 -- - add new element, modified head and tail

The problem is that List.tail model.log is Maybe List LogEntry, and I want it to be Just List LogEntry. And it could only be Just List LogEntry there, because head is also Just LogEntry.

What to do there? Nest another one case and mark one branch as unaccessible? Is there some pattern how to do this? Or function like List a -> Maybe (a, List a), that returns head and tail in the same Maybe?


Solution

  • Use pattern matching on lists (a list may be the empty list or a cons of head and tail):

    let newEntry = {
      text = model.currentText,
      timestamp = model.now,
      duration = Nothing
    }
    in case model.log of
      [] -> [newEntry]
      le :: log -> 
        let le' = { le | duration = newEntry.timestamp - le.timestamp }
        in newEntry :: le' :: log