Does it make sense to use clojurescript on front-end and haskell on back-end?

I know how to write haskell and clojure. I also wrote in clojurescript for a while.
I like both.

Haskell is great for large-scale programs. Clojure is okay for small or medium-size programs.

PureScript isn’t haskell, and its UI frameworks don’t look as mature as re-frame or fulcro.
GHCJS is slow. I don’t like sluggish UI.
ClojureScript is miles better than javascript and typescript.
Thus, clojurescript looks like a natural fit for front-end.

To be honest, I just want to have fun by writing in haskell and clojurescript. I just don’t know whether it’s a good idea to do so.

1 Like

If you ask me, I’d recommend using Clojure in the backend, for the only reason that I prefer it to Haskell.

But if you want to use Haskell as your backend, there’s nothing stopping you. You can use ClojureScript as your frontend with it just as well as you could use JavaScript.

The only difference is that you won’t be able to share any code between backend and frontend the way you could have with Clojure/ClojureScript combination, and you won’t be able to use some of the standard Clojure serialization like Transit or EDN, you’ll have to use JSON most likely. Unless you want to be the first to write a full transit implementation for Haskell and share it with the open source world!

That’s all really.

3 Likes

I’m curious why you don’t think Clojure is okay for large-size programs? (my 113K monorepo of Clojure code at work might want to have words with you)

2 Likes

People who used haskell and clojure and decided to use haskell said haskell catches type errors that clojure doesn’t catch during compile time.

In practice and theory, it can be difficult to catch where nil is passed to a function in a clojure program without extensive runtime debugging. Haskell doesn’t allow nil.

This is true although I don’t know how important it is to be able to catch type errors during compile time.

I know clojure has optional types and spec, but they aren’t the same as haskell’s compile-time type checks. Haskell has an advanced type system with advanced type inference.

1 Like

nil-punning is idiomatic in Clojure – it’s a feature, not a bug :slight_smile:

I think that people who are inclined toward Haskell are going to inherently believe Haskell and a strict static type system are “better” for large-scale development but I’m not convinced (after close to forty years of experience – spanning static and dynamic languages, including FP languages that predate Haskell).

Every bug in production got past your type system and your tests. As a study into bug fix commits in public GitHub repos said “Clojure, Haskell, Ruby and Scala all have significant negative coefficients implying that these languages are less likely than average to result in defect fixing commits.” – so there’s two dynamically-typed languages and two statically-typed languages – doing much better than many mainstream languages.

4 Likes

You don’t experience runtime type errors in clojure programs often? Haskell doesn’t allow runtime type errors because it catches type errors during compile time.

No, I don’t encounter runtime type errors “often”. I encounter logic errors.

But also bear in mind that the development process is radically different. In Haskell, you write code, you run the compiler, it tells you you’re wrong, you edit your code, you run the compiler, rinse and repeat, and eventually you run your tests, and eventually you go to production – and you’ll still find bugs.

In Clojure, you write code and run it and run tests all from your editor via a REPL as part of your development process – often getting feedback about your code and your logic faster than the edit/compile/test cycle is going to be in Haskell. Yes, I’ll still find bugs in production with Clojure – just like with Haskell – but they’ll be logic bugs (just like with Haskell).

7 Likes

How much have you written in Haskell and other languages with advanced type systems?

C doesn’t have an advanced type system although it is statically typed.

1 Like

As didibus mentioned, if you just want to have fun, go right ahead. But if you want to do something more serious, I would strongly advise you use Clojure and ClojureScript together, mostly for the following reasons:

  • Clojure gives you complete access to the Java ecosystem: you may strongly dislike Java as a language as many people (including me) do, but the fact remains that so much amazing software has been built using it, and Clojure gives you all of that for pretty much free; I haven’t used Haskell for web development, it is a really nice language, but I don’t believe it is anywhere near as mature as what Java provides in this department

  • Common (.cljc) files - this is an area where I believe Clojure/Script outshines any other technology which tries to do something similar: you can write code once which runs on both the client and server; this is one of the most amazing things about using these two languages together which I have never seen anywhere else, not even with JavaScript (I know there have been attempts at “isomorphic JavaScript” over the last few years but it isn’t quite the same thing); this becomes particularly useful for example when you want to serialize data across the wire, you can just reuse the same data structures you have on the client and server, it’s brilliant and saves a tonne of time in both coding and testing;

I don’t know Haskell that well at all, I’ve played around with it a little and like what I’ve seen so far, but also from just what I’ve seen I strongly feel Clojure is a much more practical language for most intents and purposes, especially for web development.

I also don’t buy this at all:

as I too have massive code bases written in both Clojure and especially in ClojureScript, and they haven’t given me any problems, but I’ll follow your response to seancorfield on this. :slight_smile:

1 Like

And there it is: the rallying cry of Haskell zealots everywhere “You haven’t used a real typed language if you haven’t used Haskell!” :slight_smile: (don’t worry: I’m teasing!)

My Ph.D. work in the mid-'80s was on the design and implementation of functional programming languages. Part of that work was examining type inference and expressivity. Haskell was designed by a committee of my peers, drawing on the collective experience of many of us who had experimented with language design at a bunch of universities, and it’s an amazing language because of that. And over the years since its release just over thirty years ago, it’s continued to evolve, leaning heavily on ongoing PLT research. My early career was all compilers, interpreters, and runtime systems (i.e., language VMs).

C is weakly-typed – one of the few examples of mainstream languages that really is weakly-typed (credentials: I co-wrote one of the first ANSI-validated C compilers).

Look, if you prefer Language X, that’s fine. It really is. I’ve used dozens of languages in production over the decades. I’ve learned dozens of other languages for fun along the way too. I came out of university fluent in about a dozen languages to start with. As someone with a language design and compiler writing background, I find languages very interesting, but I also have a lot of opinions based on a lot of experience that are going to be different from a lot of other programmers :slight_smile:

5 Likes

As much as people like to call Haskell’s type system “advanced”, it’s not that advanced compared to Kotlin, Scala and recent C# versions, even Java, we’re talking about the same ballpark.

I’d like to hear where Haskell has an upper hand for catching type errors relative to these, I don’t think it does honestly, but I’ve only used Haskell in personal projects, not professionally as I have those other languages.

Haskell can use complex types which allows you to type things you couldn’t in others (well except Scala, that type system is just as nuts as Haskell’s). But those advancement from my understanding doesn’t actually make it that you can statically check more type errors.

Anyways, I say that because I’ve had considerable experience writing production large scale programs with all those other ones (Scala, Kotlin, C# and Java), as I have with Clojure and I don’t have more bugs in my Clojure code, actually I often have less “critical” bug and logical bugs for the reason Sean mentioned. There’s the very rare, like once a year, runtime bug due to a type error in edge cases I didn’t catch during development, but those are the easiest to fix (they fail immediately, so rollback, fix, redeploy, takes an oncall 30min).

Haskell I’ve used only personally on small side projects, so I can’t really speak to bug amounts, since I didn’t really do a lot of QA or tracking of issues as projects were mostly toy. But what I understand of type systems, I don’t think it would do you better than Kotlin or Scala for example.

Also like Sean pointed out, I was really interested with trying to find empirical evidence for defect rates of various languages a while back, and surprisingly all research I found (but keep in mind there isn’t a lot of high quality one on that topic) found that Clojure and Haskell exhibit similar defect rates, both ranking towards the lowest defect of any language. So you’re in good hands either way. That said, similarly studies found dynamic languages like Clojure to produce better productivity.

That makes Clojure both ranking in the top for low defect and for high productivity.

And my personal annectode building large scale production systems with Clojure for the last 3 years confirms this as well.

Take it all with a grain of salt though, my research conclude with the fact that language choice actually has some of the least impact on both productivity and defects, like a 1-5% variance, so in the end, it doesn’t matter, what matters is which language you personally find the most interesting, fun, and which you are most enjoying yourself coding in as well as being productive in, and for me that’s Clojure hands down, but if that’s Haskell for you go with it!

Regards

3 Likes

I like both clojure and haskell. They are fun to play with.

Obviously, people who don’t want programs that run on javascript runtimes or JVM are not going to write in clojure. It doesn’t make sense for classes of programs to run on nodejs or JVM or web browser. Rust seems to be gaining popularity among people who want to do system programming, but I don’t like its statically linked binaries.

I don’t want to think about kotlin, java, and C#. In my knowledge, they are bad languages even if they actually have a more advanced type system than haskell does. I think I prefer clojure and haskell to scala because scala looks like a complex mess.

  • Where did you find benchmarks on defect rate and productivity?
  • Is clojure strongly typed, by the way?
1 Like

No, seriously, just no. That’s a bad hot take. You are not being at all objective about that.

Right, so be honest: this is absolutely your subjective opinion without any facts or research or data. And as I said, it’s perfectly fine to prefer Language X subjectively. But just don’t try to spin your (uninformed by science) personal opinion about other languages. I can dunk on JavaScript all day long but I know that’s my personal opnion :slight_smile:

Yes. Do not confuse strong/weak typing with static/dynamic typing.

Maybe, you can enlighten me with what you know about the languages?

Seriously? Did you not read my post about my background in language design?

What I tried to ask // What do you think about kotlin, java, C#, and Scala?

My thoughts // I wrote in java, and the way it forced class OOP everywhere frustrated me. Functional programming is simpler than class OOP which I can live without. C# is similar to java because it forces class OOP, too. Kotlin looks similar to java. Scala looks very complex. It seems I generally don’t like programming languages that focus on class OOP or make it difficult to avoid OOP. Ocaml and its derivatives have OOP but make it easy to avoid OOP. Ocaml has more focus on functional programming with immutable data structures.

What I like // Functional programming. Immutable persistent data structures. Strong types. Static typing.

What I don’t like // class OOP. Prototypical object inheritance (javascript).

You know now that I don’t like typescript, either.

1 Like

GraalVM actually did open the door to using Clojure for some of these use cases, basically think everywhere you’d use Go, you can substitute-ish with using Clojure and compiling it with GraalVM native image.

You probably still wouldn’t use it to write device drivers or things like that though (well except for industrial drivers, a lot of those are already written in Java, so I guess you could use Clojure for those).

There is an interesting dialect of Clojure here though for real-time embedded stuff: https://ferret-lang.org/ it’s still in a bit of infancy, but it’s pretty cool.

Another thing in that vein, for scripting and for use on newer Raspberry Pies and such thing, there is an interpreted Clojure dialect called Babashka here: https://babashka.org/

Hum, I didn’t really take notes of all my research. I believe I had managed to find about 5 studies into defect rates, and 3 for productivity. I’d say the defects studies if I remember, three we’re kind of poor, like they did things like take 10 people and split them in two groups each writing the same program, than seeing which group had the least defects. But there were 2 good studies that looked at a large number of public repos and used the commit message history and bug trackers to infer how often defects were found for the number of commits made.

For productivity they were all pretty poor as well, with a format similar to what I described for the poor defects one, just have like a small number of people make the same thing in different languages and measure their time to completion.

Clojure is, but ClojureScript isn’t.

That’s a good, honest, and very subjective answer. Thank you.

What do I think about Kotlin, Java, C#, and Scala?

I haven’t done much C# – just dabbled, as part of experimenting with helping to port the Mono project to non-Windows platforms years ago. I consider C# to be about equivalent to Java: it has some nice features Java doesn’t have but it also has some sharp edges Java doesn’t. I’m not very attracted to the CLR as a platform because it really isn’t as portable as the JVM (even with Mono). I quite like F#.

I did a lot of Java, from about '97 onward, but I felt Java got too big and too complex around Java 5 so I slowly drifted away from using it. When Java 8 came out, I re-evaluated it (and wrote a long blog post at corfield.org about that) but I still wouldn’t want to be writing Java for a living. It keeps improving but it’s still awfully verbose for my tastes and that weird hybrid OOP/primitive thing just doesn’t sit well with me. I attended a lot of Java conferences over the years and wrote a lot of Java.

I used Scala for a while for production work. I liked many things about it – on the functional side – and I think it’s a big improvement over Java even on the OO side. The downsides for me were the very slow compiler and the horrible error messages, especially if your transgression involved the collection types in the standard library. And I think implicit is an abomination from a language design point of view. I attended a lot of Scala conferences and user group meetings over that time too (because so many were local to me). What really turned me off Scala was the awful upgrade experience from 2.7 to 2.8 and what looked to be a similarly bad upgrade to 2.9 (my contacts in the Scala community say 2.8->2.9 wasn’t as bad but still wasn’t great, and this seems to be a problem that the Scala team still don’t seem to have a good handle on to this day). If you use Scala as a purely functional language, it’s still pretty good, but the “better Java” push for it means that there’s a huge schism in the community. In addition, the type system, while powerful, is crushingly complex – a problem that Martin is trying to address through Dotty).

I learned Kotlin for fun and I think it’s a big improvement over Java. It’s pragmatic and well-designed, within the confines of its original goals. I think they have a great story for interop and leveraging the Java ecosystem, good tooling, good documentation. If I was looking to target multiple platforms and wanted good IDE support etc, I’d be happy enough using Kotlin. I created a Kotlin compilation task for Boot, by the way, for mixed Clojure/Kotlin projects.

You didn’t ask what I think of Haskell (perhaps I’ve already answered that for you?) but I don’t find it a very practical real-world language. The tooling is fragmented and very sharp around the edges compared to what the JVM ecosystem has. The libraries are opinionated and often weird – and there certainly is not the broad range of options that the JVM ecosystem offers. I hoped that Frege and/or Eta would get traction and we’d get a serious Haskell-on-the-JVM as a player in the mainstream world but both projects have languished (and that’s partly because the Eta crowd dumped all over Frege instead of pitching in and helping with it – but it wasn’t “pure enough” for them, which is Haskell’s Achille’s heel to a tee: avoid success at all costs, eh?). I created a Frege plugin for Leiningen, by the way, for mixed Clojure/Frege(Haskell) projects.

You didn’t mention that functional programming isn’t as strong in kotlin as it is in clojure. Kotlin also lacks immutable persistent data structures which I often miss while I write in janet language for system scripts. Immutable persistent data structures create peace of mind. It is one of the most important features of clojure and haskell.

It still compiles to native binaries. Each haskell library or program is neatly translated to a linux distrubion package. I don’t like JVM jars because converting a JVM jar into a linux distribution package requires a major change in linux distribution packaging. The same can be said for npm packages. Haskell’s tooling situation improved a lot with cabal, stack, and hpack. Tooling isn’t a bottleneck anymore. Also, Cardano cryptocurrency is written in Haskell.

I prefer haskell’s build system(cabal, hpack, stack) to java’s build system(maven, ant, gradle, …). I hate maven, ant, gradle, and sbt. Clojure’s build system is better than haskell’s, though.

To produce native binaries from any JVM language, I need graalvm. I haven’t found a way to compile graalvm for gentoo linux. If you want native binaries and linux distribution packages, JVM languages aren’t going to be first-class citizens.

1 Like

“But also bear in mind that the development process is radically different. In Haskell, you write code, you run the compiler, it tells you you’re wrong, you edit your code, you run the compiler, rinse and repeat, and eventually you run your tests, and eventually you go to production – and you’ll still find bugs.”

You wouldn’t use the Haskell REPL, like with Clojure? Serious question.