I believe an apples-to-apples comparison would be:

    # before
    x
    |> then(&Map.put_new_lazy(&1, :file_path, fn -> Path.join([&1.base_path, 
&1.filename]) end))

    # after
    x
    |> Map.put_new_lazy(:file_path, &Path.join([&1.base_path, &1.filename]))

And I think it does read better.

That being said, personally I don’t think I have commonly needed something like 
this though and I’d just break out of a pipe and move on. :)
If we add this precedent, that the function receives the input as one of the 
arguments, should we update other functions for consistency too? Do we have an 
Map.update accepting a 2-arity function? (Is the map the first or the second 
argument?!)

> On 19 May 2023, at 13:30, Christian Trosclair 
> <christian.troscl...@dockyard.com> wrote:
> 
> It is sometimes if not often desirable to build up some Map or Keyword list 
> and add or update values in such a way that takes into account the current 
> state of the data, yet some of the current functions do not allow this to be 
> done from a pipe.
> 
> A trivial example for instance:
> ```
> map = %{filename: “thing.txt”}
> map = Map.put_new(map, :base_path, "/")
> map = Map.put_new(map, :file_path, Path.join([map.base_path, map.filename]))
> 
> ```
> This is begging to be piped, but Map.put_new_lazy/3’s function argument does 
> not receive the current map.
> 
> For reference Map.put_new_lazy/3
> https://github.com/elixir-lang/elixir/blob/a64d42f5d3cb6c32752af9d3312897e8cd5bb7ec/lib/elixir/lib/map.ex#L381
>  
> <https://github.com/elixir-lang/elixir/blob/a64d42f5d3cb6c32752af9d3312897e8cd5bb7ec/lib/elixir/lib/map.ex#L381>
> It is true we could simply use Kernel.then/2, but I think we can do better 
> and make code easier to scan.
> 
> An example using pipes and Kernel.then/2
> ```
> %{filename: “thing.txt”}
> |> Map.put_new(:base_path, "/")
> |> then(&(Map.put_new(&1, :file_path, Path.join([&1.base_path, 
> &1.filename]))))
> 
> ```
> Kernel.then/2 is breaking up what could be a quick scan of the code.
> 
> We can smooth this out.
> 
> Here is an implementation on Map.put_new_lazy/3
> 
> ```
> ​​  @spec put_new_lazy(map, key, ((map) -> value)) :: map
>   def put_new_lazy(map, key, fun) when is_function(fun, 1) do
>     case map do
>       %{^key => _value} ->
>         map
> 
>       %{} ->
>         put(map, key, fun.(map))
> 
>       other ->
>         :erlang.error({:badmap, other})
>     end
>   end
> 
> ```
> Then we could rewrite the original example like:
> 
> ```
> %{filename: “thing.txt”}
> |> Map.put_new(:base_path, "/")
> |> Map.put_new_lazy(:file_path, &(Path.join([&1.base_path, &1.filename]))))
> 
> ```
> If we wanted to go even further, we could even accept an arity 2 function and 
> pass in both the map and the key.
> 
> Thoughts?
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to elixir-lang-core+unsubscr...@googlegroups.com 
> <mailto:elixir-lang-core+unsubscr...@googlegroups.com>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/elixir-lang-core/bc728f96-ff11-40c1-b90f-b412e241fbd9n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/elixir-lang-core/bc728f96-ff11-40c1-b90f-b412e241fbd9n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/A62FF95B-A991-42B3-AAA1-8C4426118763%40wojtekmach.pl.

Reply via email to