Sorting List of Objects Containing Maybe Time.Posix

Viewed 202

I have a List of custom types that I would like to sort on one attribute which is of type Maybe Time.Posix. In reading the docs I've come to the conclusion I should use List.sortWith, as neither Maybe nor Time.Posix values are comparable. I've written a set of functions to prepare the values so they are comparable. The challenge that I'm facing, though, is pulling the values from the types in the list.

Here are the functions:

maybeCompare : (a -> a -> Order) -> Maybe a -> Maybe a -> Order
maybeCompare f a b =
    case a of
        Just some_a ->
            case b of
                Just some_b ->
                    f some_a some_b
                Nothing ->
                    GT
        Nothing ->
            LT

posixCompare : Time.Posix -> Time.Posix -> Order
posixCompare a b = compare (posixToMillis(a)) (posixToMillis(b))

posMay = maybeCompare (posixCompare)

Which I combine and use like this:

List.sortWith (posMay .time) objList

On data that looks like this:

obj1 = {id=1,time= Just time1}
obj2 = {id=2,time= Just time2}
obj3 = {id=3,time= Just time3}
obj4 = {id=4,time= Just time4}
obj5 = {id=5,time= Nothing}

objList = obj1 :: obj2 :: obj3 :: obj4 :: obj5 :: []

Now, this approach works for a list like this List (Maybe Time.Posix). By which I mean I get the output I expect, the list is sorted on the Posix time with the Nothing values in the desired location.

However, for a List of types where Maybe Time.Posix is one of the values I get this error (one of many, but I think this is the source):

List.sortWith (posMay .time) objList
                       ^^^^^
This .time field access function has type:

    { b | time : a } -> a

But `posMay` needs the 1st argument to be:

    Maybe Time.Posix

Is there are way to make the types of my functions align to sort this kind of data? Or, should I rethink my approach?

1 Answers

I've created a working example at https://ellie-app.com/8dp2qD6fDzBa1

Your posMay function is of the type Maybe a -> Maybe a -> Order, so it's not expecting .time, which is a function of type {id:Int,time:Maybe Posix} -> Maybe Posix.

Instead, you can create a different function which shims between posMay and List.sortWith, which would look like this: List.sortWith (\a b -> posMay a.time b.time)

If you want to be able to pass a getter function to posMay, you could rewrite it to accept that function:

posMay getter a b =
    maybeCompare posixCompare (getter a) (getter b)

Then, you would use it like this: List.sortWith (posMay .time) (or List.sortWith (posMay identity) for a List (Maybe Posix). A version that works like this is at https://ellie-app.com/8dp7gm3qthka1

Related