Having built-in lenses would be great. I've been using evancz/focus for a
while to allow the definition of generic form fields but it still required
defining a Focus function for each record field.
For example, boolField : Model -> Focus -> String -> Html Msg
[ boolField model (record => fieldA) "Field A"
, boolField model (record => fieldB) "Field B"
]
Given a Model, it's easy to read a deep field but hard to update. If the
same function would be able to both read and update a value, so much
boilerplate would disappear, including the one that was necessary with the
Focus library. We could write the following :
[ boolField model .record.deep.deeper.fieldA "Field A"
, boolField model .record.deep.deeper.fieldB "Field B)
]
Please ignore the fact that this could belong in an abstraction and not be
updated directly from the Model. Abstraction is nice to model your domain
and intent, but painful when it only serves to hide or spread boilerplate
code. Replace Model with User and the same applies regarding nested records.
On Thursday, March 9, 2017 at 6:16:26 AM UTC-5, Michael Taylor wrote:
>
> I would like to extend upon Mark's suggestion of .field= functions that
> parallel the .field functions.
>
> I find I want these as a pair more often than a setter functions on its
> own.
>
> Lets use @field as an example syntax.
>
> @field :
> { get : { a | field : b } -> b
> , set : b -> { a | field : b } -> { a | field : b }
> }
> @field =
> { get = \r -> r.field
> , set = \v r -> { r | field = v }
> }
>
>
> This is in the spirit of arturopala/elm-monocle's Lens
> <http://package.elm-lang.org/packages/arturopala/elm-monocle/1.4.0/Monocle-Lens>
>
> type, whose example:
>
> streetNameOfAddress : Lens Address String
> streetNameOfAddress =
> let
> get a = a.streetName
>
> set sn a = { a | streetName = sn }
> in
> Lens get set
>
>
> would simplify to:
>
> streetNameOfAddress : Lens Address String
> streetNameOfAddress =
> Lens @streetName
>
>
> I am using a similar lens type as part of an update composition library
> that allows simplification of:
>
> update msg model =
> case msg of
> SearchPage msg_ ->
> let
> (searchPage_, cmd) = SearchPage.update msg_
> model.searchPage
> in
> ( { model | searchPage = searchPage_ }, cmd )
>
>
> into:
>
> update msg model =
> case msg of
> SearchPage msg_ ->
> Compose.update msg_ model @searchPage SearchPage.update
>
>
> The above example of Compose.update is highly simplified, it can do much
> more than just reduce boilerplate code. I have reduced the example to
> highlight to focus on the @field syntax.
>
> Compose.update can only reduce boilerplate code if @searchPage does not
> have to be expressed as:
>
> { get = .searchPage, set = \v r -> { r | searchPage = v } }
>
>
> To this end I have a pre-elm-compile script that looks for expressions of
> the form At.field and builds an elm source file of the form:
>
> module At exposing (field, name, searchPage)
>
> field = { get = .field, set = \v r -> { r | field = v } }
> name = { get = .name, set = \v r -> { r | name = v } }
> searchPage = { get = .searchPage, set = \v r -> { r | searchPage = v } }
>
>
>
--
You received this message because you are subscribed to the Google Groups "Elm
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.