Very good.
With reference to “the expression problem”, tagged union types are complete and not dynamically extensible so they cannot be the right way to approach this. The way to make code behaviour extendable is always to pass a function. I notice that you have this in your functions where you pass in a (a -> String)
:
findEnumValue : List a -> (a -> String) -> String -> Maybe a
findEnumValue enum enumToString value =
enum
|> List.filter ((==) value << enumToString)
|> List.head
If you wanted to capture the whole Enum type as a single thing, you could do this:
type alias Enum a =
{ values : List a
, toString : a -> String
}
Then all your function signatures would be in terms of enums:
findEnumValue : Enum a -> String -> Maybe a
decodeEnumValue : Enum a -> String -> Decoder a
onEnumInput : Enum a -> (a -> msg) -> Attribute msg