Concise way of updating a nested value inside a record in Elm (0.18)

自作多情 提交于 2019-11-30 08:53:46

Your last example with the let/in syntax is as concise as is possible in Elm 0.18 without resorting to additional packages.

That being said, in functional languages, you will often find the concept of Lenses useful for updating nested records. There is an Elm package at arturopala/elm-monocle which provide the ability to construct and execute lenses for more concisely getting and setting nested record values.

Using that package, you could build up lenses that would let you do concise things like this:

personWithUpdatedCity = personCity.set "Madrid" person

getCityOfPerson = personCity.get person

The downside is that you have to write all the lens wiring code yourself. In Haskell, this wiring can be done by the compiler. In Elm, we don't have that luxury.

The Elm code needed for the above lenses would be this:

addressCityLens : Lens Address String
addressCityLens =
    Lens .city (\cn a -> { a | city = cn })

personAddressLens : Lens Person Address
personAddressLens =
    Lens .address (\a p -> { p | address = a })

personCity : Lens Person String
personCity =
    compose personAddressLens addressCityLens

As you can see, it's tedious and much more code than you may expect to set a nested value. Due to that tedium, you may want to stick to the let/in example for the time being, unless your code uses nested sets all over the place.

There is an older discussion on the topic of making setting value easier in Elm here, but it hasn't been active for some time.

Simon H

If I need to do this sort of update a lot, I build a helper

updateAddress : ( Address -> Address ) -> Model -> Model 
updateAddress fn m = 
  {m | address = fn m.address }

and use it, e.g.

updateAddress (\a -> { a | city = Madrid }) model

You can make a function that receives a Person (which is a type alias for { name: String, address: { city: String, country: String }) and a Stringand returns the updated record, like this:

updateCityAdress : Person -> String -> Person
updateCityAddress person newCity =
    { name: person.name, address = { country: person.address.country, city = newCity }

> updateCityAddress person "Madrid"
> { name = "Steven", address = { country = "Spain", city = "Madrid" } }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!