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.

Reply via email to