Zulip Chat Archive

Stream: batteries

Topic: Array.join vs Array.flatten


Eric Wieser (Mar 27 2024 at 17:13):

docs#Array.join looks the same as docs#Array.flatten to me:

/--
`O(|join L|)`. `join L` concatenates all the arrays in `L` into one array.
* `join #[#[a], #[], #[b, c], #[d, e, f]] = #[a, b, c, d, e, f]`
-/
@[inline] def join (l : Array (Array α)) : Array α := l.foldl (· ++ ·) #[]
/-- Joins array of array into a single array.

`flatten #[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` = `#[a₁, a₂, ⋯, b₁, b₂, ⋯]`
-/
def flatten (as : Array (Array α)) : Array α :=
  as.foldl (init := empty) fun r a => r ++ a

Which name should be kept?

Eric Wieser (Mar 27 2024 at 17:13):

(mentioned previously here)

Kyle Miller (Mar 27 2024 at 17:33):

join is perhaps the more common name for this monadic operation, though it appears Scala might call it flatten.

My vote would be for join.

If we wanted Lean to be friendly in a Ruby sense, I know there is an aliasing mechanism where we could make Array.flatten be an alias for Array.join — so it would elaborate as Array.join — but I'm not sure that's exposed in any command (the Lean 3 export command would let you rename identifiers, but Lean 4's doesn't). I also seem to remember there being some inconsistencies with how aliases are handled, but having more aliases could help exercise this feature.

Eric Wieser (Mar 27 2024 at 17:34):

Join matches List.join too, which is nice; though to make things more confusing, .flatten was upstreamed to core

Joe Hendrix (Mar 27 2024 at 18:11):

I think Array.join should be the exclusive one kept and upstreamed to core. I don't see any reason that can't be done prior to the next release.

Joe Hendrix (Mar 27 2024 at 18:13):

We could make Array.flatten a deprecated abbreviation for Array.join.

Mario Carneiro (Mar 27 2024 at 21:09):

I think join is a bit of a monad-brained name, it is not as natural from procedural programming languages. From the name alone I think someone would guess that it is the ++ operation

Mario Carneiro (Mar 27 2024 at 21:13):

(I have also thought the same about List.bind, which would probably be called something more like flatMap in a javascriptish language)

Kim Morrison (Mar 27 2024 at 21:19):

(When I first came to Lean it took me a while to stop writing flatMap, which was one of the most common tokens in the Scala code I used to write...)

François G. Dorais (Mar 27 2024 at 21:56):

(Aside: is flatMap in Scala join or bind?)

Ruben Van de Velde (Mar 27 2024 at 22:03):

flatMap is the monad operation, so I guess bind

Mario Carneiro (Mar 27 2024 at 22:03):

bind

François G. Dorais (Mar 27 2024 at 22:04):

I don't see any issue with having both so long as one is an alias pointing to the other. That way a quick hover will reveal they are synonyms.

Of course, it's debatable which should be the root. My preference is for the generic name (join) to be an alias for the specialized name (flatten).

James Gallicchio (Mar 28 2024 at 02:29):

François G. Dorais said:

(Aside: is flatMap in Scala join or bind?)

Scala's join is flatten, which nicely emphasizes their relationship. flatMap is map followed by flatten.

Kyle Miller (Mar 28 2024 at 02:38):

For what it's worth, I think the monad word "join" comes from generalizing the example of List.join to all monads.

Kyle Miller (Mar 28 2024 at 02:43):

I'm not sure what's it's most often called the the math literature, but it's the "multiplication" law of the monad, denoted by μ\mu. Just mentioning this to say that neither "join" nor "flatten" is the general word, at least as the math is concerned.

Mario Carneiro (Mar 28 2024 at 03:43):

I always assumed it was the other way around. It would be great to track down the history of the naming of Monad.join and List.join in haskell

Kim Morrison (Mar 28 2024 at 03:54):

Doesn't Haskell use concat for List.join?

Mario Carneiro (Mar 28 2024 at 03:58):

According to https://en.wikipedia.org/wiki/Monad_(functional_programming)#History , the first use of monads in FP is by Moggi (1989 / 1991), but he is using the standard mathematical notations only (i.e. greek letters) and does not name the operations AFAICT; and the next reference is to monads in Haskell when they were overhauling their IO system in 1993 and that paper uses bindIO for the first time but not join

Mario Carneiro (Mar 28 2024 at 03:59):

there is no explanation of why the name "bind" is chosen, it may predate the paper

Mario Carneiro (Mar 28 2024 at 04:00):

there is also no mention of "Monad" as a typeclass, I think this may also predate typeclasses

Mario Carneiro (Mar 28 2024 at 04:02):

lol @ https://wiki.haskell.org/Monad_tutorials_timeline

Mario Carneiro (Mar 28 2024 at 04:12):

Scott Morrison said:

Doesn't Haskell use concat for List.join?

Indeed Haskell's list type has concat and concatMap, although of course you can also use bind and join coming from the Monad implementation. In Haskell I think the names tend to be different on specialized types because they don't have dot-notation for disambiguation (you can also use qualified imports but this is usually not used for things in Base)

James Sully (Mar 28 2024 at 11:26):

Some people might incorrectly expect [[[1]]].flatten = [1]

Eric Wieser (Mar 28 2024 at 11:44):

That view is probably quickly dispelled when they realize that #[#[1, 2], 3] is a type error.


Last updated: May 02 2025 at 03:31 UTC