One of the really great things about having rich built-in data structures and a more-or-less purely functional data model is that it's really easy to express transformations and be confident that they work. In Java it's incredibly verbose to express & manipulate something like "a list of pairs of sets of integers" because if that was part of your core data model, you'd want to represent it in a class, and then you have all sorts of problems about what callers expect vs. what they get (e.g., do I get a reference to the original, or a copy? Can I safely mutate this?).
But if you actually have facilities to pass around and manipulate those kinds of data structures in a way with no side effects, it's trivial to verify (first on the REPL, then in your unit tests) that whatever transformation you're writing applies properly down the entire nested chain, and it will always work for anything of that pattern. And it is much quicker to write those kinds of transformations iteratively in a dynamic language than trying to represent it on a type level a la Scala.
That's a good point. A lot of what I built classes and objects for in other languages can really be expressed as simple maps, hashes, lists, and vectors, and more complex types built from them. Clojure's elevation of maps/hashes/vectors to first-class types puts it above Lisp, imho, and its functions to manipulate said data structures are better even than languages like Ruby and Python.
I can't imagine having to go back to Java collection classes again. Ugh.
but just in case someone considering clojure is worried about missing something like haskell's typeclasses (or whatever they're called in scala), it's worth mentioning that clojure does have some notions of "protocols" and "datatypes" that seem pretty similar.
They're not really comparable; Clojure protocols are a more flexible (runtime-extensible, for instance) notion of a (non-hierarchical) interface, and records / deftypes are just straight-up Java classes, with records having in addition nice map-style access to members.
I haven't used Typed Clojure, so I can't speak to that, but if you want to do type-level programming Clojure is probably not your weapon of choice.
sorry, not well-phrased: i meant to say that, taken together, clojure's datatypes and protocols look somewhat similar to haskell's typeclasses, not that datatypes and protocols are similar.
But if you actually have facilities to pass around and manipulate those kinds of data structures in a way with no side effects, it's trivial to verify (first on the REPL, then in your unit tests) that whatever transformation you're writing applies properly down the entire nested chain, and it will always work for anything of that pattern. And it is much quicker to write those kinds of transformations iteratively in a dynamic language than trying to represent it on a type level a la Scala.