[erlang-questions] Maps

Loïc Hoguin essen@REDACTED
Tue May 14 22:21:29 CEST 2013

On 05/14/2013 08:21 PM, Björn-Egil Dahlberg wrote:
> 2013/5/14 Loïc Hoguin <essen@REDACTED <mailto:essen@REDACTED>>
>     I personally would prefer a more powerful:
>        M#{ K #{ DK => DV }}
>     Because it allows you to write things like:
>        M#{ K #{ DK => DV }, K2 => V2 }
>     And update multiple levels at once.
>     I know K can be a map, but deep update only works on values, the
>     same way normal update only works on values, so no confusion is
>     possible, we're only updating values, not K itself. If you feel an
>     operator is needed it can be introduced between K and # in the two
>     examples above.
>     Programmatically this would translate as extracting the map found at
>     key K, and ensuring it's a map, updating this map with DK => DV,
>     then placing this map back into the key K in map M along with
>     setting V2 in key K2.
>     It doesn't sound hard to implement in the compiler, it's just
>     unrolling things for access and rolling back again for the actual
>     update. Exactly what we do manually today.
>     It should also be easy to compile to an optimized deep update with
>     this syntax as you got everything in a single expression.
>     Note: If you are not interested in it despite how simple it is
>     please at least ensure it can be done with a parse transform.
>     Thoughts?
> I think we want to be explicit here. Meaning using an operator and
> "seeing" the value in action. (I have bad memories of perl).
> Just some first thoughts on deep updates here to see if I get the
> intention right. What I think we need is someway to use an associated
> value within the map. I figure, something like "escaping" the key which
> would fetch the associated value. Let's use '~' in this example.
> Say I have a nested map like above, M = #{ a => #{ b => 1 }} and I would
> like to update the inner b value with it self plus four. I could write
> it like this:
> 3> M#{ a := ~a#{ b := ~b + 4 }}.
> #{ a => #{ b => 5 }}
> Another possibility would perhaps be to bind values first (wrapped in {
> .. } )and then use them in updates, say
> M#{ a := M }{ a := M#{ b := V }{ b := V + 4 } }
> .. that looks even more horrible .. =)
> I haven't given this much thought but I'm trying to get a sense of it.
> Something like this?

That's taking it even further than I thought. I would be perfectly fine 
with binding separately from updating, especially because:

   M#{ a := ~a#{ b := ~b + 4 }}.

isn't so pretty when done with some key types like:

   M#{ <<"a">> := ~<<"a">>#{ <<"b">> := ~<<"b">> + 4 }}.

Now most of what I would be using would be atoms and integers, but this 
still would be the ugliest allowed syntax ever.

It works fine if done in two steps (with the first step most likely done 
in the function clause itself).

doit(M=#{ a := A=#{ b := B }}) ->
   M#{ a := A#{ b := B + 4 }}.

Writing this I realize it's quite possible that you can already do it 
with the current EEP. Am I right?

And it also fits:

doit(M=#{ a := A=#{ b := B }, aa := yes_do_it}) ->
   M#{ a := A#{ b := B + 4 }, aa := done}.

You can already do this with records. Can we do this with maps too? This 
+ any type as key + dynamic is all I need.

It would be cool if that could also be optimized at compile time, though 
that's more of an edge case so understandable if that comes later.

Loïc Hoguin
Erlang Cowboy
Nine Nines

More information about the erlang-questions mailing list