Removing duplication; code review request

I’ve been following the Elm Guide and I’m currently on the forms section.

In trying to add validation to the model, I’ve run into some duplication across case branches - I was wondering if this could be written more elegantly? Thanks!

Ellie link

update : Msg -> Model -> Model
update msg model =
    case msg of
        NameChange name ->
            -- Review: can the following block (which repeats thrice) be refactored?
            let
                newModel =
                    { model | name = name }
            in
            { newModel | validationModel = validate newModel }

        PasswordChange password ->
            let
                newModel =
                    { model | password = password }
            in
            { newModel | validationModel = validate newModel }

        PasswordAgainChange passwordAgain ->
            let
                newModel =
                    { model | passwordAgain = passwordAgain }
            in
            { newModel | validationModel = validate newModel }

How about this: https://ellie-app.com/b9JvLXRrZa1/0

2 Likes

You could separate the concerns of validation and the rest of the model update like this:

-- rename your current Model to RawModel

type alias Model =
    { raw : RawModel
    , validated : ValidationModel
    }

update : Msg -> Model -> Model
update msg model =
    let
        newRaw = rawUpdate msg model.raw
    in
    { raw = newRaw
    , validationModel = validate newRaw
    }

rawUpdate : Msg -> RawModel -> RawModel
rawUpdate msg model =
    case msg of
        NameChange name ->
            { model | name = name }
        ...

If that seems better to you, you might also want to consider modeling the validation result as something like Result String ValidatedModel or Result (List String) ValidatedModel (that will let you more easily compose functions are your model expands to have more validations).

1 Like

Great answers, thanks!

As long as you have some post processing to do on all the branches of the case expression you could do something like this too:

update : Msg -> Model -> Model
update msg model =
    (case msg of
        NameChange name ->
            { model | name = name }

        PasswordChange password ->
            { model | password = password }

        PasswordAgainChange passwordAgain ->
            { model | passwordAgain = passwordAgain }
    )
        |> validateModel
1 Like