问题
Is it possible to update a field in an Elm record via a function (or some other way) without explicitly specifying the precise field name?
Example:
> fields = { a = 1, b = 2, c = 3 }
> updateField fields newVal fieldToUpdate = { fields | fieldToUpdate <- newVal }
> updateField fields 5 .a -- does not work
UPDATE:
To add some context, I'm trying to DRY up the following code:
UpdatePhraseInput contents ->
let currentInputFields = model.inputFields
in { model | inputFields <- { currentInputFields | phrase <- contents }}
UpdatePointsInput contents ->
let currentInputFields = model.inputFields
in { model | inputFields <- { currentInputFields | points <- contents }}
Would be really nice if I could call a mythical updateInput function like this:
UpdatePhraseInput contents -> updateInput model contents .phrase
UpdatePointsInput contents -> updateInput model contents .points
回答1:
Rolling your own update function
Yes, though perhaps not as nicely as getting from a field. But the idea is the same, you write a function that simply uses the record update syntax:
setPhrase r v = { r | phrase <- v }
setPoints r v = { r | points <- v }
updInputFields r f = { r | inputFields <- f r.inputFields }
Then you can write:
UpdatePhraseInput contents -> updInputFields model (flip setPhrase contents)
UpdatePointsInput contents -> updInputFields model (flip setPoints contents)
The Focus library
When you combine field and fieldSet, you get something like a Focus. Although that library works for more things than just records. Here's an example of what this would look like using Focus:
phrase = Focus.create .phrase (\upd r -> { r | phrase <- upd r.phrase })
points = Focus.create .points (\upd r -> { r | points <- upd r.points })
inputFields = Focus.create .inputFields (\upd r -> { r | inputFields <- upd r.inputFields})
Then you can write:
UpdatePhraseInput contents -> Focus.set (inputFields => phrase) contents model
UpdatePointsInput contents -> Focus.set (inputFields => points) contents model
回答2:
Ideally you could define a function which could select which field gets updated, but you cannot.
See This article, which explains why it's not currently possible to functionally update fields in a record in elm:
"Seasoned functional programmers will surely have noticed that many of these concepts sound a lot like lenses, and Elm actually already has a lens-like library authored by Evan himself, called Focus. This, however, does not actually solve the problem: it requires manual description of setters just like the purely function based approach does."
...and the following comment from the the creator of Elm explaining why proposed support for this wasn't added with the recent changes to records:
"I considered that and decided against it. I know that proposal. It's a language feature proposal, not a simple syntax thing"
来源:https://stackoverflow.com/questions/31770421/update-a-field-in-an-elm-lang-record-via-dot-function