Msg organisation and currying with custom types

I have this demo code, where I have a record in my model, which represents my domain object, which again contains a list of records of a related domain object (Template, which contains a list of Group). I’ve tried to create my messages for updating these records from these design goals:

  • I want my messages to clearly signal when they make sense to send and receive (my current design does this by nesting messages, since you can’t update a Group in the UI without updating the Template the group resides in)
  • The user can add an arbitrary number of Groups to a template, so I need messages to specify the exact group that is being updated (which I’ve done by putting the index of the group in the message)

I have two questions for this:
1: Am I going about this in a sensible way, or is there a more idiomatic way to do it?
2: This way of organizing Msgs would work quite nicely with currying, but it seems like I’m missing a way to do currying with types only; my workaround is putting it in a function ala:

viewGroupEditor : Int -> Group -> Html Msg
viewGroupEditor index group =
    div [] [
                input [placeholder "Group Name", value group.name, onInput (groupNameMsg index) ] []
            ]


groupNameMsg : Int -> String -> Msg
groupNameMsg index input =
    UpdateTemplate (EditGroup index (UpdateGroupName input))

Is there a way to do currying just with types?

I think there is some difficulty in the terminology you’re using.
Currying is the process of turning a multiple argument function in to nested single argument functions. This is something the Elm compiler does for all functions. All functions in Elm are curried.

You can apply an argument to a function and get back another function, the function you get back is a partially applied version of the original function. Having curried functions by default in the language makes partial application rather nice and easy. But you can do partial application of functions in some languages that don’t have curried functions.

In your code example you can compose the constructors for the various parts of your Msg type by using the function composition operators >> or <<
https://package.elm-lang.org/packages/elm/core/latest/Basics#>>

eg.

groupNameMsg : Int -> String -> Msg
groupNameMsg index input =
    UpdateGroupName >>  EditGroup index >> UpdateTemplate

You need to apply the index argument to EditGroup as it doesn’t come from the output of UpdateGroupName.

Deeply nesting values like this can be a bit of a pain, as you have to extract them again to use them. But whether this is good or a pain really depends on the use case.

1 Like

Ah yes, I’m conflating different concepts, thanks! I was not aware the two were not synonymous :slight_smile:

And the composition operator does indeed do what I want, and allows me to inline my nested messages (with operators reversed from your example); I might still pull them out for readability, but now I’m not forced to at least :blush:

viewGroupEditor : Int -> Group -> Html Msg
viewGroupEditor index group =
    div [] [
                input [placeholder "Group Name", value group.name, onInput (UpdateTemplate << EditGroup index << UpdateGroupName) ] []
           ]

(also in Ellie)

And I don’t mind nesting in general, though it depends on the problem, as you said. I’d still love to see examples of how others might choose to organize their messages in a case such as this :slight_smile:

My lack of distinction between types and type constructors was mainly due to laziness. I never had the thought that constructors aren’t special, but merely functions in disguise though; thanks for lesson :blush:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.