I came to Clojure from F#/ReasonML/C#/PHP/JavaScript so I understand the comfort in specifying something with a type system and what it's like to not have one and what it's like to have a weak/strong one
Compile time for Clojure is when you inject new code into your running program
Imagine you have a large codebase with lots of interconnected types and then you tasked the computer with checking all those types everytime you injected
Would that slow down the code injections for you and every other developer? Yes maybe, what about checking for probable errors? Again yes but slower, the feedback loop in lisps are what make them feel magic so this would be a problem
What could we do to maintain dev speed and confidence?
This is my current approach:
First is clojure-lsp (clj-kondo) this will check for silly Monday morning mistakes and do it in a separate process so I can code inject unhindered but still spot errors via my editor
Second is a new library called hyperfiddle/rcf they are inline tests that run on code injection so any static assertion I want to write about data or functions I can
They will run under "compile"/code injection time and can be solidified into "real" tests at any time and maybe more importantly serve as great communication for how to use functions and what kind of data you can expect to flow through them close to the original definitions
For me those things combined with TDD, the repl and the static analysis from intellji and writing real tests every now and again is enough confidence for me and I'm in control of the "compile" time cost not the language
So when it comes to green/red cycles in TDD the repl (code injection) is great for creating code/solutions and hyperfiddle/RCF is great for creating the safety harness required to fearlessly refactor all triggered from inside the editor it's really addictive
Barring that, Julia is a lispy language with great support for optional typing.
Both of the above will get a potentially better performance when you add types (the checks are (mostly?) done at compile time). Racket also has optional types, but I think these contracts are checked at runtime? I am not sure.
I'd think out of any language lisp would shine here.
You could write as complex of a type system as you wanted that compile time checks, so it's surprising someone hasn't written one that mimics at least java/c++/whatever style types.
I do think that is one of the down sides to lisp though. When you can do almost anything it's very hard to agree on what to actually do.
There's at least typed racket.
> I have 0 experience here but that's really surprising to me.
> I'd think out of any language lisp would shine here.
I don't think you should be surprised that people don't want to write their typecheckers as macros. A few people might want to do that, but most people don't. And at this point you're not far from just creating a new language, that you could create in ML or a descendant, which have always been one of the most popular options for that.
Fortunately, people have already done the work for you. [1]
And while I don't know the scope of the library, if they have a way to not allow dynamic features then you're already starting from a having a typed language (with one library dependency).
Only now you can keep building up the type system in ways that benefit your project, unlike in most non lisp languages.