All I really want is:
```elm
{ model.something | more = 42 }
```
søndag 14. august 2016 02.49.07 UTC+2 skrev OvermindDL1 følgende:
>
> Just a passing idea to perhaps help give ideas for better methods:
>
>
> Updating a nested record is a bit convoluted as something like:
> ```elm
> let
> something = model.something
> in
> { model | something = { something | more = 42 } }
> ```
> Excepting the let/in part because Elm does not support an expression as
> the first argument (`model` and `something` in these cases) for
> I-have-no-clue-reason, and another language I work often in is Elixir, its
> syntax for the above would be similar:
> ```elixir
> %{ model | something: %{ model.something | more: 42 } }
> ```
>
> However, that is painful, so Elixir has a couple of helper functions that
> simplify that kind of work, let me demonstrate, this does the same as the
> above:
> ```elixir
> put_in models, [:something, :more], 42
> ```
> And you can go arbitrarily deep and it returns a new model with the path
> altered to the given value as necessary. Elixir also has lispy macros so
> you can also use the above function via:
> ```elixir
> put_in models.something.more, 42
> ```
> Basically using 'read' syntax to specify the path, but it gets expanded to
> the above at compile-time. It also supports not only records but also maps
> (dicts in elm), lists (also lists in elm) and anything else that follows
> the Access protocol (a set of functions of certain types to do basic
> functions), but those are the default.
>
> It has extra features like this, say `model.something` is a `List Int` in
> elm parlance:
> ```elixir
> put_in model, [:something, Access.all], 42
> ```
> This will set any and all values in the list at model.something to 42, not
> terribly useful, however it has a lot more functions as well, such as (I
> want to use more 'elmy' syntax, so I will now use things like `.something`
> instead of `:something` and no commas between arguments, only in tuples and
> lists and such):
> ```elixir
> -- Where model = { something : Dict String (List Int) }
> ( oldValue, newModel ) = get_and_update_in model [ .something, "joe",
> Access.at(0) ] (\oldValue -> let oldValue = Maybe.withDefault 0 in (
> oldValue, Just (oldValue+1) ))
> ```
> This will update a value in and let you return a value (anything you wish)
> within a tuple. This one will access `Dict.get "joe" model.something` and
> get the returned list, accessing the first element (`at` for lists, `elem`
> for a tuple index starting at 0 as well), and the called passed in function
> returns a tuple where the first element is the first element of the
> returned tuple and the second element is what the thing at the path will be
> updated to, so this case will return the `oldValue+1` if it existed, if it
> did not then it returns 1 due to the `withDefault 0`.
>
> More functions it adds are:
> ```elixir
> -- Where model = { something : Dict String (List Int) }
> value = get_in model [ .something, "joe", Access.at(2) ] -- Returns the
> value at the path
>
> values = get_in model [ .something, Access.all, Access.at(2) ] -- Returns
> all of the values 2nd values in the lists in all the values of the
> dictionary as a list if they exist, else they are skipped
>
> pop_in model [ .something, Access.all, Access.at(2) ] -- Removes the
> element in the list at position 2 in all the dictionary values if it
> exists, if it does not exist then it skips it
>
> update_in model [ .something, Access.all, Access.at(2) ] (\oldValue ->
> Just (( oldValue |> Maybe.withDefault 0 ) + 4)) -- Updates a value(s)
> in-place
> ```
> Along with macro's for the read-format pathing, which is not needed here.
>
> The keylist (the `[ .something, Access.all, Access.at(2) ]` in the last
> example) can also take functions, whatever they return (empty list,
> single-element list, multiple-element list, etc...) will be what is used
> and what is set back.
>
>
> *Thus*, what would be thought of Elm adding in functions like these
> (HKT's might be needed, not thought through the implementation yet, only
> the API):
> ```
> type Access
> = All
> | At Int
> | Elem Int
> | Key recordKeyType {- Whatever recordKeyType might be as an indicator
> for a key on a record -}
> | DictKey dictKeyType
> | Fn (EnumerableType -> EnumerableType) {- This is why I think HKT's
> might be needed, or special caseing in the compiler -}
>
> -- You'd need some kind of EnumerableType as well, no doubt opaque or
> something, or need HKT's, probably need HKT's in general, Elm really badly
> needs HKT's...
>
> {-| Get a value calculated from the old value and set a new value
> simultaneously -}
> getAndUpdateIn
> : List Access
> -> (Maybe valueType -> ( retValue, Maybe valueType ))
> -> EnumerableType
> -> ( List retValue, EnumerableType )
>
>
> {-| Gets a value from an access path -}
> getIn
> : List Access
> -> EnumerableType
> -> List retValue
>
>
> {-| Removes a value from a given path if possible, returning it if it
> exists -}
> popIn
> : List Access
> -> EnumerableType
> -> ( List retValue, EnumerableType )
>
>
> {-| Sets a value(s) at the given path -}
> putIn
> : List Access
> -> newValue
> -> EnumerableType
> -> EnumerableType
>
>
> {-| Updates a value in the path and returns the new modified object -}
> updateIn
> : List Access
> -> (Maybe oldValue -> Maybe newValue )
> -> EnumerableType
> -> EnumerableType
> ```
>
> These could then be used like:
> ```
> -- Where model = { something : Dict String (List Int) }
> -- With values of: model = { something = Dict.fromList [("joe", [1, 2,
> 3]), ("beth", [10, 11, 12, 13])] }
>
>
> ( oldValue, newModel ) = model |> getAndUpdateIn [ Key .something, DictKey
> "joe", All] (\v -> ( v, v |> Maybe.withDefault 0 |> (+) 1 ))
> -- Will return `oldValue == 1`
> -- And returns `newModel == { something = Dict.fromList [("joe", [2, 2,
> 3]), ("beth", [10, 11, 12, 13])] }`
>
>
> newModel = model |> putIn [ Key .something, All ] [ 42 ]
> -- Will return `newModel == { something = Dict.fromList [("joe", [42]),
> ("beth", [42])] }````
>
>
> newModel = model |> updateIn [ Key .something, Fn (\dict -> dict |>
> Dict.filter (\k v -> (String.length k) >= 4 ) ) ] (\v -> v)
> -- Will return `newModel == { something = Dict.fromList [("beth", [10,
> 11, 12, 13])] }`
> -- This is because we used a Fn to return the set of things we want to
> operate over and as such will only assign those back, allowing us to filter
> out things with ease.
> ```
>
> This style makes doing very complex embedded enumerable updating with
> ease. However as the above is proposed it would likely require Higher Kind
> Types in Elm, which does not have those yet, thus for now just implementing
> the above for just records would be sufficient for a good portion if not
> the overwhelming majority of program, and that could be done without HKT's.
>
--
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.