I understand the equivalent to flatMap
in Scala is mapcat in Clojure.
I have an inkling that mapcat
in clojure only works with sequences, unli
The real difference is that flatMap is polymorphic on the type, and mapcat isn't. So any type can decide to provide a "flatMap" like behaviour. That's how you get things like Futures being flatMapable.
In Clojure, mapcat is specific to the seqable type. Any seqable can be coerced into a sequence, and all sequence can be mapped and concatenated. The mapcat implementation will check if the input is seqable, if so, it will call seq on it to coerce it to a sequence, and then it will map and cat that sequence and give you back a sequence. You don't get back a result of the original type.
In Scala, if you implement IterableLike trait (I think that's the right interface), you get the default flatMap implementation which is a bit like the Clojure one minus the coercion to sequence. But, many types also provide a custom implementation of flatMap, making it generic in that way.
I know a little about Scala but it seems to me flatMap is the Scala bind function in a monad and mapcat is a possible implementation of the bind function for the sequence monad in Clojure. So they are the same for sequences.
But Scala for example has a flatMap function for Futures: it takes a future and a mapping function and returns a future that will complete after input future completes. This operation doesn't seem to be a simple mapcat in Clojure. It may be realized this way instead
(defn flat-map [f mv] (mapcat (fn [v] (future (f @v))) mv))
So, no. They are not the same, neither in terms of what they operate on. In Scala flatMap is the common name for different functions and for example Futures' flatMap coordinates input and output futures. A simple mapcat in Clojure won't work because it won't return a future.
They seem very similar and appear to work on the same kind of things. From looking at the documentation and examples I can't see a functional difference.
mapcat
works on sequences, and just about every clojure data type can be a sequence. If you pass something that is not already a seq
to mapcat
it will call seq on it automatically, so in practice you can pass just about all clojure values to mapcat. If you want to iterate over a tree you would need to call prewalk
or postwalk
to specify the traversal order.
In the standard Scala library: Responder, Future, Parser, ControlContext. None of them are sequences or particularly sequence-like. There is also a slight variation in ParseResult.