I'm looking at doing some interop between clojure and scala. As java itself now has lambdas, I was thinking of a generalisation between data and how to apply a function to a collection
- clojure functions extend
clojure.lang.IFn
and generalises collection operations onclojure.lang.ISeq
- scala functions extend
scala.Function
and generalises collection operations onscala.collection.Traversable
- java lambdas extend
java.util.function.Function
and generalises collection operations onjava.util.stream.Stream
Questions:
- Would monads be useful in this case?
- If so, would a
map
operation be implemented across all collection types and how might this be generalisable?
Example:
(map (scala-fn +)
[1 2 3]
(scala-seq [1 2 3])
(.stream [1 2 3]))
=> (scala-seq [3 6 9])
Continued (added haskell as a tag just in case the hardcore type people might know)
There are operations in both Clojure, Scala and Java that take a collection, applies a function to that collection and returns a new collection.
- All of these languages run on the JVM.
- However, each language defines it's own class to represent a function.
I'm more familiar with clojure, so there are operations like:
(into {} [[:a 1] [:b 2]]) => {:a 1 :b 2}
Which converts a clojure vector into a clojure map. Because the into
operation generalises on java.util.List
any datastructure that inherits java.util.List
can be used.
I wish to work with some scala libraries in clojure and face certain obstacles:
- Scala, like clojure also has immutable data structures, but they are defined very differently from clojure data structures
- Scala functions inherit from
scala.Function
and so need to be wrapped toclojure.lang.IFn
Scala datastructures do not inherit from
java.util.List
which means that:(into {} (scala-list [:a 1] [:b 2]))
will not work.I'm looking to reimplement some basic clojure functions that also incorporate scala datastructures. (map, reduce, mapcat, etc...)
The functionality would look something like:
(into {} (scala-list [:a 1] [:b 2])) => {:a 1 :b 2}
(into (scala-map) [[:a 1] [:b 2]]) => (scala-map :a 1 :b 2)
(concat (scala-list 1 2) [3 4]) => (scala-list 1 2 3 4)
(concat [1 2] (scala-list 3 4)) => (1 2 3 4) ;lazy seq
(map + [1 2] (scala-list 3 4)) => [4 6]
(map (scala-fn +) [1 2] (scala-list 3 4)) => [4 6]
- What I'm looking for is the ability to use both clojure and scala functions in collection operations.
- I can do this without using monads (by checking the collection and function types and doing some coercing before function application)
- What I'm asking here serves as a bit of a curiosity for me, as all the literature I've read on monads seem to presume that any function
f:X->Y
is universal. - However, in the case of clojure/scala/lambda interop, a clojure function, a scala function and a java lambda are not universal. I'm curious about how category theory might be used to solve this problem.
Functions
aren't tied toscala.collection.Traversable
in any significant way). 3) "Would monads be useful" - for what case? You haven't asked anything yet. 4) "Would amap
operation be implemented [...]" - it's already implemented on every thinkable and unthinkable collection, and also on everything that vaguely resembles a functor. Unclear what you're asking. - Andrey Tyukinmap
. It seems like it's taking(scala-fn +)
which reduces lists of integers to integers (ie.List[Int] => Int
), and something that looks roughly likeList[Seq[Int]]
, and produces aSeq[Int]
. That corresponds tosequence
operation onTraverse
, followed by an ordinarymap
. Maybe take a look atTraverse
to reformulate the question more clearly. - Andrey Tyukinmap
operation can be generalized over all container types (and more). In Haskell, this is called aFunctor
, and the generalized function is called fmap. However, it's impossible to derive this automatically for all interesting cases (though it could be done for some), so it has to be provided for each container. Monads are not really useful for that; but one of the requirements for Monads is that the underlying Monad type is a functor. So for every Monad, such a generalized map must exist. - dirkt