What does HackerNews think of coalton?
Coalton is an efficient, statically typed functional programming language that supercharges Common Lisp.
"With Scala you feel smart having just got something to work in a beautiful way but when you look around the room to tell your clojure colleague how clever you are, you notice he left 3 hours ago and there is a post-it saying use a Map." --Daniel Worthington-Bodart
> On the contrary, they're still the most effective technique we've found for improving program correctness at low cost.
This is not borne out by research, such as there is any of any quality: https://danluu.com/empirical-pl/ The best intervention to improve correctness, if not already being done, is code review: https://twitter.com/hillelogram/status/1120495752969641986 This doesn't necessarily mean dynamic types are better, just that if static types are better, they aren't tremendously so to obviously show in studies, unlike code review benefit studies.
My own bias is in favor of dynamic types, though I think the way Common Lisp does it is a lot better than Python (plus Lisp is flexible enough in other ways to let static type enthusiasts have their cake and eat it too https://github.com/coalton-lang/coalton), and Python better than PHP, and PHP better than JS. And I prefer Java to PHP and JS. Just like not all static type systems are C, not all dynamic type systems are JS. Untyped langs like assembly or Forth are interesting but I don't have enough experience.
I don't find the argument that valuable though, since I think just focusing on dynamic vs static is one of the least interesting division points when comparing languages or practices, and may be a matter of preferred style, like baseball pitching, more than anything. If we're trading experience takes I think Clojure's immutable-by-default prevents more bugs than any statically typed language that is mutable by default; that is, default mutable or default immutable (and this goes for collections too) is a much more important property than static types or dynamic types. It's not exactly a low cost intervention though, and when you really need to optimize you'll be encouraged by the profiler to replace some things with Java native arrays and so on. I don't think changing to static types would make a quality difference (especially when things like spec exist to get many of the same or more benefits) and would also not be a low cost intervention.
Some domains also demand tools beyond type proofs. i.e. things like TLA+. I think adding static types on top of that isn't very valuable, similar to adding static types on top of immutable-by-default isn't very valuable.
Last quip to reflect on. "What's true of every bug found in the field? ... It passed the type checker. ... It passed all the tests. Okay. So now what do you do? Right? I think we're in this world I'd like to call guardrail programming. Right? It's really sad. We're like: I can make change because I have tests. Who does that? Who drives their car around banging against the guardrail saying, "Whoa! I'm glad I've got these guardrails because I'd never make it to the show on time."" --Rich Hickey (https://www.infoq.com/presentations/Simple-Made-Easy/)
And of course if you really want an ML style BDSM type system in Common Lisp there's Coalton[1].
People should do basic research before writing something silly like this. Qualifying your statement with 'usually' is just a chicken sh*t approach. Common Lisp and Racket have optional strong typing, leaving the responsibility and choice to the developer. Common Lisp is great for implementing compilers. You also have things like Typed Racket and Coalton. The latter is completely statically typed ala MLTON
:= (ALTER-TABLE (:IF-EXISTS? :ONLY?) :*? +)
| ...
:= ...
Despite using S-expressions, this is parseable with as much rigor as more free-form character syntax.I think Coalton [1] is a good example of this. The language is embedded as S-expressions in Common Lisp, but you get Rust-like error messages, showing exact source lines (with line numbers) and embedded underlines showing the location of the offending code.
With that said, what is true is that if you're using Common-Lisp-style macros and you're manipulating S-expressions programmatically, lexical information may get thrown out. This is not unlike doing a bunch of string manipulation in an ORM to generate SQL, which will have similarly poor error messages.
Coalton made a lot of design decisions to work away from issues that this post describes.
- Coalton dispensed with ML's module system of structures, signatures, and functors. No doubt a beautiful concept, and sometimes satisfying to write, but almost always unsatisfying to use due to how explicit one tends to need to be. Like the author suggests, the "interface-style" of type classes or traits has always felt more intuitive, despite losing the ability to have multiple implementations of an interface for a single type. (However, I've come to appreciate that different interfaces should require different types—as opposed to one type having many interfaces.) Coalton uses type classes.
- Coalton has S-expression syntax. No indent rules. No precedence rules. No expression delimiters. All of the "tradition" of ML syntax is dispensed with into something that is a lot easier to read and write for complex programs... yes, provided you use ParEdit or similar
- It should be no surprise that with S-expressions, you get Lisp-style macros. Macros in Coalton are just Common Lisp macros. No separate pre-processors. No additional language semantics to deal with. Arbitrary compile-time computation and/or codegen, completely integrated.
- Because it's built on Common Lisp, Coalton gets something few (if any?) other ML-derivatives get: Truly incremental and interactive development. You can re-compile types, functions, etc. and try them out immediately. There's no separate "interpreter mode"; just a Lisp REPL.
Coalton's language features are still settling (e.g., records are being implemented) and the standard library [2] is still evolving. However, it's been used for "serious" applications, like implementing a compiler module for quantum programs [3].
[1] https://github.com/coalton-lang/coalton
[2] https://coalton-lang.github.io/reference/
[3] https://coalton-lang.github.io/20220906-quantum-compiler/
Type checking can remove an entire class of bugs from even being a consideration. Yes, it could be argued that type mismatches are a trivial class of bug, and yes, proper testing should catch any issues... but catching problems before you go to testing can save you precious seconds, especially when coding in the typical interactive style of Lisp. Lisp lets you code at amazingly high velocity, good support for type checking helps increase that velocity even further.
Opinions on Coalton in Common Lisp?
I've brought the library up many times because CL, unlike so many other languages, really lets you extend it. Want a static type system? https://github.com/coalton-lang/coalton/ Want pattern matching? No need to wait for PEP 636, https://github.com/guicho271828/trivia/ If all that keeps someone from trying CL, or from enjoying it as much as they could because of some frustration or another, due to lacking out of the box, chances are it is available through a library. (Or heck, even just tooling setup. Tab completion for symbols and jumping to function definitions are just two great things modern programmers enjoy in all sorts of languages, CL too, if someone doesn't have that setup I wonder if they must enjoy pain.)
Rust, because I finally made it from beginner to intermediate level (at least I think).
https://flix.dev/ looks very cool.
Also, recently someone posted this here on HN: https://github.com/coalton-lang/coalton
It's a statically-typed, functional language embedded in Lisp, with many of the FP goodies.
SBCL? Or ECL (compiles to C), CLASP (C++, LLVM)?
The older ThinLisp? (compiles a subset of CL to C) https://github.com/ska80/thinlisp
The very new NPT, a CL implementation in C? https://github.com/nptcl
> Static typing for ahead-of-time more-correct programs
the Coalton library. A ML/Haskell as a CL library. https://github.com/coalton-lang/coalton/
> Static typing for faster or leaner programs
SBCL
> WebAssembly
Common Lisp running natively over WebAssembly: https://news.ycombinator.com/item?id=31590819 (very much POC)
I know, I know, but he didn't mention any of these in the blog post, nor any CL project. Justice is done.
For a type-racket equivalent, we now have Coalton, it's like a Haskell on top of CL: https://github.com/coalton-lang/coalton/ Its author says:
--
Take this with a grain of salt, because I’m neither a user nor expert of Typed Racket, but:
Typed Racket focuses more on the gradual typing of a given program. It has lots of features to make that easier, such as occurrence typing. Coalton is a separate, embedded language.
Typed Racket achieves polymorphism through subtyping and and first-order type variables. Coalton achieves polymorphism through type variables, higher-kinded types, and type classes.
Coalton, like ML and Haskell, focuses on defining objects by their properties and supported functions. This is a proposed way of having modular, reusable code. Typed Racket, as far as I can tell, has no such features.
Coalton code can be fully inferred, so type annotations are not necessary. Typed Racket cannot.
All in all, I think the biggest and most important take-away is that Typed Racket goes through great effort to seamlessly blend with ordinary Racket. But that means Typed Racket has to compromise on type system features that can only be supported if you’re willing to change the language itself.Coalton puts the type system first, opting for something close to Haskell, at the expense of not being a system for gradually typing Common Lisp, and instead being a separate language altogether.
---
They use it for their open-source quantum compiler and other things.
It adds static typing to Common Lisp, while (I believe) still allowing one to escape to the dynamic world when needed. Sure, there are statically-typed languages, but I don't know of another dynamic language in which something like Coalton has been done.
Assuming you can convince people to give emacs a try (shouldn't be hard if they're convinced to give Lisp a try and otherwise don't have preexisting biases against emacs for other reasons), getting setup for Lisp is as easy as installing Portacle (https://portacle.github.io/). It and any decent Lisp setup includes things like a hotkey to autocomplete, so you just type 'typ' and tab or whatever, and out pops suggestions like 'type', 'typep', 'type-of', ... and so you don't have to remember spelling; similarly they all should have some sort of intellisense to minimize trips to the CLHS or jumps to source code. I'm a vim head (which is why I don't know what newbie setups are like anymore apart from doing it in vim) but even when I type "(getf " I'm shown at the bottom "(getf PLACE INDICATOR &OPTIONAL (DEFAULT NIL))". If that's not enough, I can jump to source with "ctrl+]" (really nice being able to jump to the Lisp implementation's source for built-ins too without having to do anything special -- can even modify it live by adding print statements or whatever I want), or typing ",s" to get the symbol's describe output (I mainly like it for getting the docstring -- if memory serves though Portacle gives you the docstring with the lambda list in an intellisense popup automatically, like a Java IDE), and if I really need to ",h" opens a browser tab to the hyperspec page on that symbol.
If Portacle isn't one's cup of tea, it becomes a bit harder, but I don't think it's "orders of magnitude" harder... Compared to setting up a local (L|W)AMP environment back in the mid-late 2000s, which tons of teens learning PHP did, it's a piece of cake. You install a Lisp implementation (like SBCL -- http://www.sbcl.org/platform-table.html if your distro doesn't package it/have a recent version), configure it to use Quicklisp (a couple commands -- https://www.quicklisp.org/beta/), and consult the CL Cookbook for further basic steps on setting up the best environment you can for a variety of editors (https://lispcookbook.github.io/cl-cookbook/editor-support.ht... -- emacs, vim, VS Code, Atom, Sublime...).
For scaling, CL has scaled to multi-million lines of code projects, it scales fine. If you want more sophisticated type checking, there have been solutions over time, but in case you missed the latest and greatest take on it: https://github.com/coalton-lang/coalton
Every time I've described to people on the internet what makes Lisp nice, I've been met with a riposte that such aspects aren't unique to Lisp—be them interactive/incremental development, macros, efficient machine code, editor integration, whatever—or that a laundry list of features means nothing and instead Lisp's value should somehow be proven through its (hitherto comparatively dismal) popularity with employers and software engineers. I myself have definitely given up on an academic approach to proselytizing the language, and instead have just focused my energy in building applications and libraries people (especially employers) find useful, at smaller cost and in shorter time than other people are able to provide.
It's like classical music. I can't convince you such music is incredibly rich and pleasant, especially not by talking about the harmonic theory of common practice. Instead, you just have to listen and agree or disagree, I think.
And Lisp certainly has no secrets; it's old as can be and extraordinarily and thoroughly documented. Countless people (myself included) have spilled ink on the (alleged) virtues of Lisp. It's all out there.
When it comes down to it, it's an incredibly flexible language useful for prototyping and rapid development, while at the same time supporting everything you need to transform your application into a rock solid, robust, static binary. All of Lisp's features balance in such a way that developer time and energy are prioritized and consequently optimized.
P.S., Like a sibling comment mentioned, you can have Haskell-level static typing in Common Lisp with Coalton: https://github.com/coalton-lang/coalton
That said, Common Lisp while dynamically typed, is also strongly typed. Many type errors are prevented at runtime. Also you can declare types and have some limited form of static type checking in SBCL.
Verification may be interesting, for high-assurance (e.g. automotive/aerospace) applications. It's for this reason that a theorem prover[2] and an ml[3] have been implemented, and they interoperate freely with the rest of common lisp.
In other words: we are already where you want to be, and we are even less stratified than you propose we would need to be.
0. https://github.com/marcoheisig/Petalisp
1. https://github.com/froggey/mezzano/
> Coalton is an efficient, statically typed functional programming language that supercharges Common Lisp
Literally all of these things are present in Common Lisp (ok the static types "full experience" leads you to something like Coalton: https://github.com/coalton-lang/coalton however the plain SBCL experience does have some compile-time type checking). Meanwhile many so-called modern languages still lack Lisp's incremental compilation let alone the full interactive development experience such a feature can help support, an OOP system as flexible as CLOS, they can't gracefully manipulate their own code as data, they don't have anything like the condition system...
Theres a small community [0] of people who decided to try out Coalton [1], which is a Common Lisp DSL that has a strict, Haskell-like type system, and has strict evaluation (not lazy) semantics. Pattern matching, algebraic data types, all that jazz are supported directly in a Common Lisp environment.
For example, here is a function to read in the first problem's data, which makes use of the usual high order functions (map and filter), as well as currying (only one argument provided to /=, making it curried):
(declare read-aoc-data (Unit -> (List Integer)))
(define (read-aoc-data _)
"Read the data for problem 1."
(let ((data (fromSome "Couldn't read AOC1 data."
(read-file-into-string aoc1-input-file))))
(map parse-int-or-fail
(filter (/= "") (split-string #\Newline data)))))
Type annotations, as in any good ML, are optional (except when there are polymorphism bugs, like one found during AoC!). Unlike Haskell, purity isn't demanded.There's a small contest [2] with all sorts of prizes for doing AoC in Coalton and contributing back to the project through tutorials, PRs, and bug reports.
[0] They hang out on Discord https://discord.gg/cPb6Bc4xAH
Fortunately, people have already done the work for you. [1]