Re: [elixir-core:12080] [Proposal] Add List.prepend and List.append to easily pipe this operations

2025-06-05 Thread benjamin...@gmail.com
[el|list] is pipeable as well, and if you are working with Erlang 
strings/binaries you can 
use https://www.erlang.org/doc/apps/stdlib/string.html#pad/4

I think it’s important not to stare us self blind on a specific syntax. All 
the functions there are currently available helps highlighting that the 
lists we have in the BEAM are double linked list. 

When I first read this thread all I could think about was that it could 
create more confusion for new developers who might believe that our lists 
are arrays. 

Although you can easily write your own macro or functions to deal with 
this, I don’t see the value in adding it to stdlib at this point. However, 
I do see value in expanding the documentation with examples on what to do 
in situations like these as they are excellent cases.

On Wednesday, June 4, 2025 at 11:15:47 PM UTC+2 william.l...@cargosense.com 
wrote:

> benjamin...@gmail.com good point about `:lists.append/2` being available. 
> But I don't see how you can prepend with `:lists.flatten/2` in a way that's 
> pipe-able. Can you show an example?
>
>
> On Wed, Jun 4, 2025 at 4:53 PM benjamin...@gmail.com <
> benjamin...@gmail.com> wrote:
>
>> You can pipe into append and prepend today with 
>> https://www.erlang.org/doc/apps/stdlib/lists.html#append/2 and 
>> https://www.erlang.org/doc/apps/stdlib/lists.html#flatten/2
>>
>> This feels like more of a documentation issue than something missing in 
>> the stdlib.
>>
>> On Monday, June 2, 2025 at 10:17:37 PM UTC+2 william.l...@cargosense.com 
>> wrote:
>>
>>> I'm for adding `List` functions that make piping easier and help with 
>>> discoverability. Though I agree they won't often be the best choice for the 
>>> reasons discussed.
>>>
>>> I will note that I think there are actually 4 operations that need to be 
>>> considered if the goal is pipe-ergonomics (names TBD):
>>>
>>> defmodule List do
>>> # For a new single element
>>> def prepend(list, x), do: [x | list]
>>> def append(list, x), do: list ++ [x]
>>> # For a new list
>>> def prepend_list(list, new_list), do: new_list ++ list
>>> def append_list(list, new_list), do: list ++ new_list
>>> end
>>>
>>> I think a clear distinction between functions that take an element and 
>>> functions that take a list is crucial. In this thread I saw a few instances 
>>> where `x ++ list` was needed but `[x | list]` was used instead, which I 
>>> think highlights that the mistake is easy to make.
>>>
>>> As for needing both `prepend_list` and `append_list`, making `++` 
>>> pipe-able is only convenient if both argument orders are available. 
>>> Otherwise, you have to drop back into intermediate variables or `then` to 
>>> get a `prepend_list`.
>>>
>>> I'll also note that I'm at like a 6/10 on this feature: I'm on the 
>>> pro-side of the fence but not by a lot.
>>>
>>> On Fri, May 30, 2025 at 6:35 PM Christopher Keele  
>>> wrote:
>>>
>>>> > We do have Enum.concat/2 and typically we don't repeat functions in 
>>>> the Enum module within the List module.
>>>>
>>>> I would argue that it wouldn't be a repetition as there would be a 
>>>> material difference between them: List.concat would obey ++ semantics, 
>>>> meaning 1) it would only work with actual lists as a first argument rather 
>>>> than any Enumberable and runtime error otherwise, but hopefully be caught 
>>>> by typing systems; and 2) allow construction of improper lists via 
>>>> non-list 
>>>> non-Enumberables in the second argument. Sometimes that's desired 
>>>> behaviour 
>>>> but it does feel footgunny now that I say it, though. Certainly something 
>>>> that would need to be outlined in the function docs if implemented, it 
>>>> does 
>>>> give me some pause.
>>>>
>>>> > My biggest concern is that I don't think piping to prepend leads to 
>>>> easier to read code here, because you have to reverse the order in your 
>>>> head (the order you read the lines is the opposite of the order it will 
>>>> appear in the list).
>>>>
>>>> I agree the provided example can be confusing way to model many 
>>>> solutions, and may be an indicator of a need for a simpler refactor. But I 
>>>> think your point is orthogonal to the List.prepend discussion—the same 
>>>> problem exists when chaining [ | ] through intermediate variables.

Re: [elixir-core:12078] [Proposal] Add List.prepend and List.append to easily pipe this operations

2025-06-04 Thread benjamin...@gmail.com
You can pipe into append and prepend today 
with https://www.erlang.org/doc/apps/stdlib/lists.html#append/2 and 
https://www.erlang.org/doc/apps/stdlib/lists.html#flatten/2

This feels like more of a documentation issue than something missing in the 
stdlib.

On Monday, June 2, 2025 at 10:17:37 PM UTC+2 william.l...@cargosense.com 
wrote:

> I'm for adding `List` functions that make piping easier and help with 
> discoverability. Though I agree they won't often be the best choice for the 
> reasons discussed.
>
> I will note that I think there are actually 4 operations that need to be 
> considered if the goal is pipe-ergonomics (names TBD):
>
> defmodule List do
> # For a new single element
> def prepend(list, x), do: [x | list]
> def append(list, x), do: list ++ [x]
> # For a new list
> def prepend_list(list, new_list), do: new_list ++ list
> def append_list(list, new_list), do: list ++ new_list
> end
>
> I think a clear distinction between functions that take an element and 
> functions that take a list is crucial. In this thread I saw a few instances 
> where `x ++ list` was needed but `[x | list]` was used instead, which I 
> think highlights that the mistake is easy to make.
>
> As for needing both `prepend_list` and `append_list`, making `++` 
> pipe-able is only convenient if both argument orders are available. 
> Otherwise, you have to drop back into intermediate variables or `then` to 
> get a `prepend_list`.
>
> I'll also note that I'm at like a 6/10 on this feature: I'm on the 
> pro-side of the fence but not by a lot.
>
> On Fri, May 30, 2025 at 6:35 PM Christopher Keele  
> wrote:
>
>> > We do have Enum.concat/2 and typically we don't repeat functions in the 
>> Enum module within the List module.
>>
>> I would argue that it wouldn't be a repetition as there would be a 
>> material difference between them: List.concat would obey ++ semantics, 
>> meaning 1) it would only work with actual lists as a first argument rather 
>> than any Enumberable and runtime error otherwise, but hopefully be caught 
>> by typing systems; and 2) allow construction of improper lists via non-list 
>> non-Enumberables in the second argument. Sometimes that's desired behaviour 
>> but it does feel footgunny now that I say it, though. Certainly something 
>> that would need to be outlined in the function docs if implemented, it does 
>> give me some pause.
>>
>> > My biggest concern is that I don't think piping to prepend leads to 
>> easier to read code here, because you have to reverse the order in your 
>> head (the order you read the lines is the opposite of the order it will 
>> appear in the list).
>>
>> I agree the provided example can be confusing way to model many 
>> solutions, and may be an indicator of a need for a simpler refactor. But I 
>> think your point is orthogonal to the List.prepend discussion—the same 
>> problem exists when chaining [ | ] through intermediate variables. It's a 
>> (valid) argument against prepending at all, not against this API. For 
>> example, an experienced Elixirist will know they'll need to pipe the result 
>> of a recursive defp-function-implemented reduce into a :lists.reverse at 
>> the end, regardless of the API they used to prepend along the way—and 
>> sometimes piping into a prepend would save noisy intermediate variables 
>> along the way. I do not see the availability of List.prepend greatly 
>> influencing developers to build backwards lists more often when 
>> inappropriate, but we may disagree there.
>>
>> FWIW my usecase is almost never chaining multiple prepends—usually I 
>> reach for it as a finisher when map/reducing a series of transforms on a 
>> list of dynamic values, and adding a special case/hardcoded value at the 
>> end; same with the proposed List.concat. The ergonomics of the pipe 
>> operator truly shine in these map/reduces, so it can be painful to have to 
>> create an intermediate variable just to use the literal operators to 
>> conclude building the desired list. As an example, mapping over a database 
>> table to create options for a select, and wanting to prepend the null 
>> option that is not modeled in the source data set.
>>
>>
>> On Friday, May 30, 2025 at 4:47:40 PM UTC-5 José Valim wrote:
>>
>>> We do have Enum.concat/2 and typically we don't repeat functions in the 
>>> Enum module within the List module.
>>>
>>> My biggest concern is that I don't think piping to prepend leads to 
>>> easier to read code here, because you have to reverse the order in your 
>>> head (the order you read the lines is the opposite of the order it will 
>>> appear in the list)
>>>
>>> Given this code:
>>>
>>>
>>> dto.ledger.accounts
>>> |> Enum.reject(fn %{account_number: acc_number} ->
>>>   acc_number in [debit_acc_number, credit_acc_number]
>>> end)
>>> |> then(fn accounts -> [get_ordered_debit_accounts() | accounts])
>>> |> then(fn accounts -> [get_ordered_credit_accounts() | accounts] 
>>> end)
>>> |> then(fn accounts 

Re: [elixir-core:12081] [Proposal] Add List.prepend and List.append to easily pipe this operations

2025-06-05 Thread benjamin...@gmail.com
And we can’t forget about https://hexdocs.pm/elixir/List.html#insert_at/3
On Thursday, June 5, 2025 at 9:26:16 AM UTC+2 benjamin...@gmail.com wrote:

> [el|list] is pipeable as well, and if you are working with Erlang 
> strings/binaries you can use 
> https://www.erlang.org/doc/apps/stdlib/string.html#pad/4
>
> I think it’s important not to stare us self blind on a specific syntax. 
> All the functions there are currently available helps highlighting that the 
> lists we have in the BEAM are double linked list. 
>
> When I first read this thread all I could think about was that it could 
> create more confusion for new developers who might believe that our lists 
> are arrays. 
>
> Although you can easily write your own macro or functions to deal with 
> this, I don’t see the value in adding it to stdlib at this point. However, 
> I do see value in expanding the documentation with examples on what to do 
> in situations like these as they are excellent cases.
>
> On Wednesday, June 4, 2025 at 11:15:47 PM UTC+2 
> william.l...@cargosense.com wrote:
>
>> benjamin...@gmail.com good point about `:lists.append/2` being 
>> available. But I don't see how you can prepend with `:lists.flatten/2` in a 
>> way that's pipe-able. Can you show an example?
>>
>>
>> On Wed, Jun 4, 2025 at 4:53 PM benjamin...@gmail.com <
>> benjamin...@gmail.com> wrote:
>>
>>> You can pipe into append and prepend today with 
>>> https://www.erlang.org/doc/apps/stdlib/lists.html#append/2 and 
>>> https://www.erlang.org/doc/apps/stdlib/lists.html#flatten/2
>>>
>>> This feels like more of a documentation issue than something missing in 
>>> the stdlib.
>>>
>>> On Monday, June 2, 2025 at 10:17:37 PM UTC+2 william.l...@cargosense.com 
>>> wrote:
>>>
>>>> I'm for adding `List` functions that make piping easier and help with 
>>>> discoverability. Though I agree they won't often be the best choice for 
>>>> the 
>>>> reasons discussed.
>>>>
>>>> I will note that I think there are actually 4 operations that need to 
>>>> be considered if the goal is pipe-ergonomics (names TBD):
>>>>
>>>> defmodule List do
>>>> # For a new single element
>>>> def prepend(list, x), do: [x | list]
>>>> def append(list, x), do: list ++ [x]
>>>> # For a new list
>>>> def prepend_list(list, new_list), do: new_list ++ list
>>>> def append_list(list, new_list), do: list ++ new_list
>>>> end
>>>>
>>>> I think a clear distinction between functions that take an element and 
>>>> functions that take a list is crucial. In this thread I saw a few 
>>>> instances 
>>>> where `x ++ list` was needed but `[x | list]` was used instead, which I 
>>>> think highlights that the mistake is easy to make.
>>>>
>>>> As for needing both `prepend_list` and `append_list`, making `++` 
>>>> pipe-able is only convenient if both argument orders are available. 
>>>> Otherwise, you have to drop back into intermediate variables or `then` to 
>>>> get a `prepend_list`.
>>>>
>>>> I'll also note that I'm at like a 6/10 on this feature: I'm on the 
>>>> pro-side of the fence but not by a lot.
>>>>
>>>> On Fri, May 30, 2025 at 6:35 PM Christopher Keele  
>>>> wrote:
>>>>
>>>>> > We do have Enum.concat/2 and typically we don't repeat functions in 
>>>>> the Enum module within the List module.
>>>>>
>>>>> I would argue that it wouldn't be a repetition as there would be a 
>>>>> material difference between them: List.concat would obey ++ semantics, 
>>>>> meaning 1) it would only work with actual lists as a first argument 
>>>>> rather 
>>>>> than any Enumberable and runtime error otherwise, but hopefully be caught 
>>>>> by typing systems; and 2) allow construction of improper lists via 
>>>>> non-list 
>>>>> non-Enumberables in the second argument. Sometimes that's desired 
>>>>> behaviour 
>>>>> but it does feel footgunny now that I say it, though. Certainly something 
>>>>> that would need to be outlined in the function docs if implemented, it 
>>>>> does 
>>>>> give me some pause.
>>>>>
>>>>> > My biggest concern is that I don't think piping to prepend leads to 
>>