Hi!
I'm trying Elm in a small project: a job posting aggregator. I am trying to use List.sortBy to sort a list of Job records by different fields, which have differing types.
Using a union type to dispatch the field that sortBy will sort on seems to require that each field will have the same type. Fair enough, but I can't figure out another elegant way to get the behavior I want.
Here's what I mean. Job listings have the following model:
type alias Model = {jobs : Maybe Jobs}
type alias Jobs = List Job
type alias Job =
{ title : String
, organization : String
, division : String
, urlDetail : String
, dateClosing : String
, salaryWaged : Bool
, salaryAmount : Float
}
On the page, jobs are presented as a simple table. You can click any of the table headings to sort the table on that field:
table []
(
[ tr []
[ th [onClick address (SortJobs Title)] [text "Title"]
, th [onClick address (SortJobs Organization)] [text "Organization"]
, th [onClick address (SortJobs Salary)] [text "Salary/Wage"]
, th [onClick address (SortJobs ClosingDate)] [text "Closing Date"]
]
]
-- ... and then the table body where each Job is a row
)
SortJobs is an Action wired to the function sortJobs:
sortJobs : SortingCriteria -> Model -> Model
sortJobs criteria model =
let currentJobsList =
case model.jobs of
Nothing -> []
Just js -> js
sortField =
case criteria of
Title -> .title
Organization -> .organization
Division -> .division
Salary -> .salaryAmount
ClosingDate -> .dateClosing
sortedCurrentList = List.sortBy sortField currentJobsList
in
if currentJobsList == sortedCurrentList
then { model | jobs = Just (List.reverse sortedCurrentList) }
else { model | jobs = Just sortedCurrentList }
... and the SortingCriteria union type:
type SortingCriteria
= Title -- corresponds to Job.title : String
| Organization -- corresponds to Job.organization : String
| Division -- corresponds to Job.division : String
| Salary -- corresponds to Job.salary : Float
| ClosingDate -- corresponds to Job.dateClosing : String
Trying to compile all of this produces the following error:
Detected errors in 1 module.
-- TYPE MISMATCH ----------------------------------------------- src/listing.elm
The type annotation for `sortJobs` does not match its definition.
67│ sortJobs : SortingCriteria -> Model -> Model
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The type annotation is saying:
SortingCriteria
-> { jobs : Maybe (List { ..., salaryAmount : Float }) }
-> { jobs : Maybe (List { ..., salaryAmount : Float }) }
But I am inferring that the definition has this type:
SortingCriteria
-> { jobs : Maybe (List { ..., salaryAmount : String }) }
-> { jobs : Maybe (List { ..., salaryAmount : String }) }
I think this is saying I can dispatch sortBy on any number of fields, as long as those fields are all the same type.
That's simple to understand (although I'm still a newbie, so the "why" is beyond me). If this is the case, though, I'm stumped about achieving my intended behavior.
Can anyone give me a hint?
Thanks!