Type over record with a certain field

I have a couple lists of different structures. They have little in common, except for a start time (and end time, but it is handled differently) I want to put all this information together into new records. I don’t want to put the different lists into one data structure, but I would like to treat some of the operations on each list - e.g. next available time - similarly. I haven’t been able to find a way to represent this in elm.

I tried this

type alias TimedRecord a = {a|start: Posix}
type TimeSeries a = TimeSeries (Maybe (TimedRecord a)) (List (TimedRecord a))

But I’m not able to construct an instance - it seems to want a record with anything except start so it can add a start field to it.


Leaving the record generic and putting the record type on just the function that deals with start time doesn’t seem to work either.

Here is a version that compiles


But, this all seems very tricky to me. I would prefer copying the business logic in this case, even though it goes against your intuition.

I do still want to think about this problem and overall way of doing the three-way based merge, but I found a workable solution to this particular problem.

I was thinking how List a can handle arbitrary operations just fine. Since my type had a list, I extracted a map (actually map head, which is what I need) This removed the time-specific part, which also allows renaming.

type Series a = Series (Maybe a) (List a)

seriesMapNext : (a -> b) -> Series a -> Maybe b
seriesMapNext f (Series _ upcoming) =
    |> List.head
    |> Maybe.map f

Adding a specific helper for time, I found the point where this function needs the time-specific signature. I made an alias for that extra stuff, because every function upstream that calls it also needs this signature.

type alias TimeSeries a = Series {a|start:Posix}

seriesNextTime : TimeSeries a -> Maybe Int
seriesNextTime =
  seriesMapNext (.start >> Time.posixToMillis)

I can’t say I’m completely clear why this form works and the other form doesn’t, but separating the functions was extremely hlepfull. Writing this, it might be the ability to declare the “record with time” version on certain functions, while still being able to declare the generic Series type on the structures that actually contain that field.

It does lose some of the “identity” of the type though
