The hardest objective problem in computer science may be P ?= NP, but the hardest subjective problem is whether it is better to have static vs. dynamic typing in languages. There are extremely intelligent, thoughtful people on both sides... and it's rare in software engineering that there is such an even divide. I'm quite familiar with Haskell, Scala, Clojure, and many other languages... and I still can't conclusively call one better. I prefer static, on a mix of practical grounds, but I realize that it's not a clear victory.
Take the concept of data frames from R, also seen in Python's Pandas library, and probably inspired by the APL family's (column-oriented) tables. It's not a complex concept. Yet it's very powerful for interactive data exploration. It's also a bitch to statically type (see: https://github.com/acowley/Frames). It's more of a leap than lenses (and probably, like lenses, extremely cool once you fully "get" it).
If we have to pull out some advanced Haskell extensions to do something basic in interactive data analysis then I consider that worrying. (This is not to say that Frames isn't a great piece of work. Bringing subtyping into a Hindley-Milner derived language and not having everything go to hell is really hard. See: Scala) And remember, this is coming from someone who's pretty invested in the "static" side.
Clojure also has a world-class aesthetic sense. Haskell is still using camelCase. OCaml uses under_scores; that's better than fuckingUglyCamelCase, but not ideal. Clojure (and the Lisp family in general) is run by people who realize that aesthetics are really important and that allowing hyphenated-tokens is far better than allowing people who hate their space bars to write "a-1" when they should be writing "a - 1". That's just one example. For another, maps. Clojure has {"five" 5, "ten" 10} but Haskell has fromList [("five", 5), ("ten", 10)]. My point is that (which I prefer Haskell, for its types) Clojure's aesthetic sense is arguably better, and I would say world-class, especially considering that it runs on a butt-ugly platform (JVM) and is still a beautiful language. We need to keep watching that community closely because they're doing some great work in a wide variety of fields, including front-end development (ClojureScript).
Type systems don't just make you write annotations; they force you to structure your code around type-checkability. This is inevitable, since type checking is by definition a specific kind of syntactic reasoning.
There is some truth around that. Just to get data frames, you need row types which means you have subtyping, and that complicates type checking considerably. Haskell (see Frames) uses multiple "experts only" language extensions to get something that "just works" for casual use but requires advanced knowledge to grok the types. It's great work, but its difficulty shows that we can't just ignore subtyping.
The counter-argument that I'd make is that 95+ percent (maybe more?) of all functions that are ever written ought to have simple static types. So much of code, when it is clean, is already well-typed, even in a dynlang. The difference is that, in a static language, the compiler yells any time someone fucks that up in refactoring. And, more generally, you learn about errors (not all errors, but a surprising percentage of them) sooner and that's a good thing. In a dynamically typed language, you see a lot of functions that evolve into multimethods that do different things per input type(s) and (although usually this won't happen if the code is maintained by decent designers) you can get O(n2) or worse complexity in the functionality. If you're programming defensively in a dynlang, you have to think about all the crap that might be passed into your functions. "What's a Matrix plus a Scalar? How about a RowVector plus a ColumnVector? How about a Sparse2DArray plus a DataFrame?"
On the whole, I'd rather be in a statically-typed language for a program of any size, and I'm stodgy and conservative and old (but efficient and concise) so, for me, "big code" starts around a couple thousand lines. I hate writing boilerplate unit tests that a compiler and a type system would knock out automatically. But I do have to give Clojure a lot of props for its community and its aesthetic sense, and I think that the above obviously derive from its ease-of-use and its Lisp heritage, both of which are tied to a feature (dynamic typing) that I otherwise wouldn't much like.
The main question that I've been pondering for a few years (and not coming to satisfactory answers) is whether it's possible to unify the cleanness-of-language and aesthetics of Clojure/Lisp with the static typing of Haskell... and not get some hyper-complex type system that results in compile-speed problems at scale (e.g. Scala under typical use). It's an open problem.
Take the concept of data frames from R, also seen in Python's Pandas library, and probably inspired by the APL family's (column-oriented) tables. It's not a complex concept. Yet it's very powerful for interactive data exploration. It's also a bitch to statically type (see: https://github.com/acowley/Frames). It's more of a leap than lenses (and probably, like lenses, extremely cool once you fully "get" it).
If we have to pull out some advanced Haskell extensions to do something basic in interactive data analysis then I consider that worrying. (This is not to say that Frames isn't a great piece of work. Bringing subtyping into a Hindley-Milner derived language and not having everything go to hell is really hard. See: Scala) And remember, this is coming from someone who's pretty invested in the "static" side.
Clojure also has a world-class aesthetic sense. Haskell is still using camelCase. OCaml uses under_scores; that's better than fuckingUglyCamelCase, but not ideal. Clojure (and the Lisp family in general) is run by people who realize that aesthetics are really important and that allowing hyphenated-tokens is far better than allowing people who hate their space bars to write "a-1" when they should be writing "a - 1". That's just one example. For another, maps. Clojure has {"five" 5, "ten" 10} but Haskell has fromList [("five", 5), ("ten", 10)]. My point is that (which I prefer Haskell, for its types) Clojure's aesthetic sense is arguably better, and I would say world-class, especially considering that it runs on a butt-ugly platform (JVM) and is still a beautiful language. We need to keep watching that community closely because they're doing some great work in a wide variety of fields, including front-end development (ClojureScript).
Type systems don't just make you write annotations; they force you to structure your code around type-checkability. This is inevitable, since type checking is by definition a specific kind of syntactic reasoning.
There is some truth around that. Just to get data frames, you need row types which means you have subtyping, and that complicates type checking considerably. Haskell (see Frames) uses multiple "experts only" language extensions to get something that "just works" for casual use but requires advanced knowledge to grok the types. It's great work, but its difficulty shows that we can't just ignore subtyping.
The counter-argument that I'd make is that 95+ percent (maybe more?) of all functions that are ever written ought to have simple static types. So much of code, when it is clean, is already well-typed, even in a dynlang. The difference is that, in a static language, the compiler yells any time someone fucks that up in refactoring. And, more generally, you learn about errors (not all errors, but a surprising percentage of them) sooner and that's a good thing. In a dynamically typed language, you see a lot of functions that evolve into multimethods that do different things per input type(s) and (although usually this won't happen if the code is maintained by decent designers) you can get O(n2) or worse complexity in the functionality. If you're programming defensively in a dynlang, you have to think about all the crap that might be passed into your functions. "What's a Matrix plus a Scalar? How about a RowVector plus a ColumnVector? How about a Sparse2DArray plus a DataFrame?"
On the whole, I'd rather be in a statically-typed language for a program of any size, and I'm stodgy and conservative and old (but efficient and concise) so, for me, "big code" starts around a couple thousand lines. I hate writing boilerplate unit tests that a compiler and a type system would knock out automatically. But I do have to give Clojure a lot of props for its community and its aesthetic sense, and I think that the above obviously derive from its ease-of-use and its Lisp heritage, both of which are tied to a feature (dynamic typing) that I otherwise wouldn't much like.
The main question that I've been pondering for a few years (and not coming to satisfactory answers) is whether it's possible to unify the cleanness-of-language and aesthetics of Clojure/Lisp with the static typing of Haskell... and not get some hyper-complex type system that results in compile-speed problems at scale (e.g. Scala under typical use). It's an open problem.