Throughout eta-lang.org we use a custom syntax highlighter we developed for CodeMirror (used in the playground) and Pygments for the static code examples throughout the docs. We will translate these to other platforms like Emacs, Vim, Eclipse, IntelliJ, etc. once IDE support is better.
You can use JVM debugging tools and with a guide on how to interpret the results for Eta (or a tool that does the mapping to Eta source code for you), debugging can be pretty awesome. The implementation was specifically designed to re-use the JVM Thread stack as much as possible so that you can get stack traces and figure out the source of the error. You'll get stack traces similar to other JVM languages like Scala and Clojure. See http://eta-lang.org/docs/html/eta-user-guide.html#debugging-... for an example. You can use tools like slf4j-ext as java agents and get nice traces - it's how I debug the Eta runtime.
Have you considered replacing the example entirely? A toy program that looks good but is terribly nonperformant is exactly what I'd put up if I wanted to make a Haskell-style language look bad.
Performance of a tiny code sample is not why people select one language over another. If that was the case, no one would be using anything besides assembly or C. Even in other languages, you'll use an abstraction heavy implementation for the benefit of long-term maintenance and code evolution and then performance optimise the bits that can pack a punch. Performance optimisation in any language looks ugly be it C or Haskell.
There are plans to make the compiler self-hoisting once it's more stable. The little bit of C used is just to turn on an option in the GHC runtime for profiling purposes. That would be replaced with some Java code to turn on an option in the Eta runtime if it were self-hoisting.
Lisp is sexy, but parenthesis are a really hard sell for the wide crowd. It sounds silly, but that's the reality. If they had forced people to learn & use Lisp instead of C, the world might be a very different place. I personally love them even now when I look back at Clojure code.
Clojurescript is just wonderful. I'm not even sure a Haskell-like language that compiles to JavaScript (Elm, PureScript, GHCJS) with really good tooling can beat it, though I haven't tried. Would be an interesting experiment to do a comparison by writing the same app in all the languages.
Thanks for bringing this up! I will definitely add a section for explaining the benefits for Scala and Clojure devs. I shipped a non-trivial Clojure web service to production that was handling 1M/requests a day. The experience is what made me finally understand that the JVM is wonderful platform, and what prompted me to work on Eta, given that Frege was insufficient for what I wanted (not supporting a lot of useful GHC extensions). Clojure was wonderful in the fact that I could become as concise as I wanted via EDSLs, and the immutability by default + concurrency primitive were a joy. The lack a type system (please don't mention core.typed) and compile-time errors at runtime were really a pain. I'm sure you can ameliorate that with libraries like prismatic/schema (which I did) and strong test discipline, but it's great when the compiler just takes care of all of that for you. Once you really "get" Haskell-like languages, you miss the benefits no matter what language you try. As for Scala, I haven't built anything significant and I wouldn't want to for some of the examples I've seen. It's too verbose for a typed functional language.
I find that you still need the same tests using a statically typed language that you would need using Clojure. The reason being that the type system does little to ensure semantic correctness.
For example, consider a sort function. The types can tell me that I passed in a collection of a particular type and I got a collection of the same type back. However, what I really want to know is that the collection contains the same elements, and that they're in order. This is what you really care about at the end of the day, does the function do what I intended.
This is difficult to express using most type systems out there. You could use dependent to express that, but it certainly wouldn't be something that you get for free with Haskell.
So, you'll still have to write tests to ensure that the function is semantically correct for anything non-trivial.
It's also worth noting that Clojure Spec lets me express exactly what I care about using the same language semantics I'm already using to write regular Clojure code:
The specification will check that the arguments follow the expected pattern, and that the result is sorted, and I can do an arbitrary runtime check using the arguments and the result. In this case it can verify that the returned items match the input.
I should mention that a good testing discipline is required in Eta as well but you would focus your testing on high-level properties using frameworks like QuickCheck. Moreover, you don't lose as much if you don't write tests like you would in dynamic languages like Clojure.
Thanks for the example! My point was not that you can't test effectively in Clojure, but just that doing things like refactoring is much easier in Eta because of the numerous static checks.
My experience is that you just use different strategies for structuring your code. Static typing allows you to write monolithic projects that have lots of internal interdependencies.
This is where the ease of refactoring with static typing comes into play. An argument could be made that static typing facilitates writing code that has a lot of coupling between components.
Dynamic typing forces you to break things up into independent components much more aggressively. I think that it's a very good thing. Low coupling allows for higher code reuse, and reduced mental overhead when reasoning about code.
If you look at the Clojure ecosystem, most of it consists of small focused libraries that solve a particular problem.
Conversely, projects are structured using small independent modules that implement a particular piece of functionality. These modules can be tested at the API level.
When I make any changes, I run the API tests and if those pass, then I know that the modules does what it's supposed to. Now we also have Spec that makes it even easier to express constraints and document intent of the code.
I've never found the need to do TDD or have unit tests when working with Clojure. When I'm developing new functionality, I use the REPL, and I know exactly what my code is doing at any time.
Once the functionality is implemented and the code is doing what I need, I turn the REPL session into tests at that point.
"Dynamic typing forces you to break things up into independent components much more aggressively."
I have the opposite experience with Haskell vs. Common Lisp or Python, but possibly because Haskell is purely functional, while CL and Python are imperative. I tend to write smaller functions in Haskell, where in CL and Python I create bigger functions with intermediate variables and bindings.
Another reason is probably absence of keyword arguments in Haskell which kind of forces you to make functions in Haskell to do only one thing and not too many things.
Yeah, I definitely think that the functional style coupled with immutability plays a huge factor.
However, I'm not referring to writing shorter functions in that comment, but rather about higher level components like namespaces.
Refactoring becomes painful when a particular piece of data is used in many parts of the application. When you change the shape of that data, then you have to make sure you update every place that uses it. This is where static typing can help ensure that you didn't miss anything in your refactoring.
I think it might interest you that Haskell-like languages are one of the best languages for programming EDSLs after Lisp-like languages. If I recall correctly, Standard Chartered uses an EDSL written in Haskell that's maintained by ~10 Haskell programmers and the remaining ~90 people program inside of this EDSL for specifying new rules. Similar case for Facebook and their spam filter rules.
You would be correct if we branded it as "the" powerful language, but we used "a" meaning it's one of many for you, the programmer to chose. I have practically found Haskell-like languages to deliver lots of value in business settings and I want to bring those advantages to everyone who would like to take advantage of it, reducing the risk of adoption as much as possible. No user ever cared about the programming paradigm, but I think they would be happy if bugs were fixed faster (or not present in the first place) or if new features were added without breaking existing features.