gleam-lang / stdlib

🎁 Gleam's standard library
https://hexdocs.pm/gleam_stdlib/
Apache License 2.0
450 stars 161 forks source link

Adding a `list.return` function #569

Closed mooreryan closed 4 months ago

mooreryan commented 4 months ago

Would there be any interest in adding a return function to the list module? Something like this:

pub fn return(a: a) -> List(a) {
  [a]
}

Maybe it is too trivial for the stdlib list module, but I have been using it from a utils module in cases where a function in a pipeline needs a list, something like this for example:

an_int |> list.return |> a_fun_that_accepts_an_int_list

It seems like a reasonable function to have to complement the list.flat_map.

Additionally, this "return" function is (essentially) implicitly present in the option and result modules as you can do this:

let _ = foo |> Some |> a_fun_that_accepts_an_option

let _ = bar |> Ok |> a_fun_that_accepts_a_result

(For reference, here is a link to docs for an OCaml example of this.)

lpil commented 4 months ago

Sounds good! Though we'd want a descriptive name rather than using the deprecated Haskell one

mooreryan commented 4 months ago

Though we'd want a descriptive name rather than using the deprecated Haskell one

I'm not really sure what you mean by this being a deprecated Haskell name. I suppose the Haskell-y name would be pure? But I'm used to the function being called return in OCaml.

Though, I suppose it is true that neither return nor pure sound very "Gleam-y"....

mooreryan commented 4 months ago

By the way, I could open a pull request for this if a name could be decided.

mooreryan commented 4 months ago

What about from, from_element, from_value, from_item, or something similar. It could fit in with the from_* pattern found in other stdlib modules

E.g.,

$ rg 'fn from[_(]' src/
src/gleam/dict.gleam
65:pub fn from_list(list: List(#(k, v))) -> Dict(k, v) {

src/gleam/option.gleam
130:pub fn from_result(result: Result(a, e)) -> Option(a) {

src/gleam/queue.gleam
38:pub fn from_list(list: List(a)) -> Queue(a) {

src/gleam/regex.gleam
89:pub fn from_string(pattern: String) -> Result(Regex, CompileError) {

src/gleam/string_builder.gleam
77:pub fn from_strings(strings: List(String)) -> StringBuilder {
101:pub fn from_string(string: String) -> StringBuilder {

src/gleam/bytes_builder.gleam
132:pub fn from_string(string: String) -> BytesBuilder {
142:pub fn from_string_builder(builder: StringBuilder) -> BytesBuilder {
151:pub fn from_bit_array(bits: BitArray) -> BytesBuilder {

src/gleam/bit_array.gleam
11:pub fn from_string(x: String) -> BitArray

src/gleam/dynamic.gleam
30:pub fn from(a) -> Dynamic {

src/gleam/iterator.gleam
118:pub fn from_list(list: List(element)) -> Iterator(element) {

src/gleam/set.gleam
149:pub fn from_list(members: List(member)) -> Set(member) {

src/gleam/string.gleam
761:pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String
lpil commented 4 months ago

In Elixir they call it wrap, I quite like that

mooreryan commented 4 months ago

wrap seems like a fine name.

I checked Elixir's wrap function and it doesn't behave in the way that makes sense for a return or pure function: (Elixir wrap docs).

Wraps term in a list if this is not list.

If term is already a list, it returns the list. If term is nil, it returns an empty list.

Not sure if the different semantics could potentially cause confusion.

lpil commented 4 months ago

Yeah I do find their one a bit odd. We can go the same way that Haskell does here.

mooreryan commented 4 months ago

Okay, just to be on the same page, this is what you are thinking?

Eg

list.wrap(1) // => [1]
list.wrap([1, 2]) // => [[1, 2]]
list.wrap([[]]) // => [[[]]]
list.wrap(Nil) // => [Nil]
lpil commented 4 months ago

Yes please!

ayazhafiz commented 4 months ago

Just to call it out, another popular option is singleton, e.g. in Java. That may or may not be more familiar to some subsections of developers.