Opinion: this is great. The aversion of Lispers to static types is historical rather than intrinsic and reflects the relative difference in expressiveness between program semantics and type semantics (and runtime vs tooling) for much of computing. Now that types and tools are advancing, static Lisps are feasible, and I love that.
This perceived inflexibility is what my comment was getting at - that for primitive type systems available back in the 80's, yes, the types significantly constrained the programs you could write. With today's type systems, however, you have far more flexibility, especially those with "Any" types that allow you to "punch a hole in the type system", so to speak.
When I tried typed Python a few years ago, I found out that, to my surprise, 99% of the code that I naturally wrote could have static types attached (or inferred) without modification because of the flexibility of Python's type system.
I also learned that types are a property of programs, more than just languages. If a program is ill-typed, then having a dynamically-typed language will not save you - it will just crash at runtime. Static types are limiting when either (1) they prevent you from writing/expressing well-typed programs because of the inexpressiveness of the type system or (2) it's burdensome to actually express the type to the compiler.
Modern languages and tools present massive advances in both of those areas. Type systems are massively more expressive, so the "false negative" area of valid programs that can't be expressed is much, much smaller. And, with type inference and more expressive types, not only do you sometimes not have to express the type in your source code at all (when it's inferred), but when you do, it's often easier.
The "Any" type is really what steals the show. I don't think that there's a lot of value in a fully statically-typed Lisp where you can't have dynamic values at all - but I think there's a lot of value in a Lisp with a Python-like type system where you start out static and can use "unknown", "any", and "object" to selectively add dynamic types when needed.
Because, being a Lisper, you probably think like me, I'll give you the idea that really convinced me that types are positive value (as opposed to "only" being small negative value): they enable you to build large, complex, and alive systems.
Types are a force-multiplier for our limited human brains. With types, you can more easily build large systems, you can more easily refactor, you can start with a live REPL and more easily transition your code into source on disk. Types help you design and build things - which is why we use Lisps, after all!
I don't want static types in a high level language.
It's just counterproductive.
We only have to look at numbers to feel how it sucks. If we divide two integers in Common Lisp, if the division is exact, the object that comes out is an integer. Otherwise we get a ratio object. Or if we take a square root of a real, we get a complex number if the input is negative, otherwise real.
This cannot be modeled effectively in a static system. You can use a sum type, but that's just a greenspunned ad hoc dynamic type.
Haven't that been feasible for a pretty long time already? Judging by how well-received (or not) they've been, it seems there isn't much demand for it. Things like clojure.spec and alike (compile-time + run-time typing) seems much more popular, but isn't static.
To be honest, I'd kill for a Lisp that had the same type system as OCaml, but I suspect the closes we'll get is basically Rust (whose macro system is quite good).
Also its small size would make it a perfect target to compile to typescript/deno/wasm without rejecting the s-exp power and runtime possibilities in its full chicken code at the backend...
A recent paper (see also the presentation on YouTube):
Leonard Oest O'Leary, Mathis Laroche, and Marc Feeley A R4RS Compliant REPL in 7 KB
For systems with a C compiler:
Vincent St-Amour and Marc Feeley. PICOBIT: A Compact Scheme System for Microcontrollers. (This one got a best paper award).
Finally, there is also PICBIT available for PIC microcontrollers:
PICBIT: A Scheme System for the PIC Microcontroller
You even get a REPL and everything WHILE running on the hardware. Super easy to set up and get going. Though as it is interpreted so you will of course not have native performance. Still very useful for prototyping and hobbyist projects.
Even interpreted on a several hundred MHz classic RISC microcontroller, Lisp will chew through a million cons cells a second or more - an order of magnitude or so faster than the old Lisp machines in the 80s were and they used to run giant CAD systems on those to design aircraft and stuff. (Albeit slowly...)
I'm not sure about how people would feel about this. I have mixed feelings. It feels like a loss of many things. What are the gains from ditching continuations?
> What is needed is a small, portable compiler that generates more or less "natural" C code with minimal dependencies and runtime system that supports at least the basic constructs of the language and that puts an emphasis on producing efficient code, even if some of the more powerful features of Scheme are not available.
Since C doesn't support continuations, it is not possible to have continuations and at the same time generate "natural" C code.
Consider how you would implement first class continuations. It's not possible to do CPS transformation (given the goal of natural code generation) - since that's a whole program transformation.
Since CHICKEN actually does this, I'll add the proviso of "without a GC or costly runtime".
Plus honestly most of the uses of continuations that would make sense in the sort of relatively low level code this is aimed at can be built out of a few special purpose macros (and possibly a small amount of crying) - scheme code tends to lean on first class continuations for a lot of things that don't really need them, Because It Can.
e.g. Paul Graham's On Lisp shows how to build (a subset of) continuations out of macros, and getting something like clojure's 'recur' out of that would probably give you simpler macros than pg's code uses.
I will be watching this closely!
With the Ableton Live Notes API, enabling something similar is one of the things I plan on adding to Scheme for Max this year.
Thanks for the tip about who wrote it, I will look him up!
The freestanding macro suggests most of the heavy lifting is done. Stuff the GPU targets will struggle with in no particular order:
- setjmp / longjmp
- signals (if used?)
- threads
- fast alloc/free
- stack will be smaller than chicken expects
I don't know how to do signals. The rest are merely difficult.
Isn't that mostly needed by call/cc, which is not supported by Crunch?
Notable is the lack of call/cc, but in my "armchair expert" opinion, it's the ugliest part of the language. Yes, continuations as a first-class object are elegant and succinct, but in order to do anything actually useful with them (like implementing exceptions), you need library code, which makes them much less composable.
I think there's a much more pleasant and practical language lurking somewhere between R6RS "big" and traditional "small" Scheme, but I feel it would take a BDFL to flesh it out.
(Meanwhile, back to fixing my init.el.)
(define (main) (display "Hello world\n"))
Doesn't compile, but instead gives error: Error: main: global variable `scheme#display' has unknown type (import (chicken bitwise) (chicken fixnum))
(define (popcount32 x) ; From "Hacker's Delight"
; (assume
(let ((x (fx- x (bitwise-and (arithmetic-shift x -1) #x55555555))))
(let ((x (fx+ (bitwise-and x #x33333333)
(bitwise-and (arithmetic-shift x -2) #x33333333))))
(let ((x (bitwise-and (fx+ x (arithmetic-shift x -4)) #x0F0F0F0F)))
(let ((x (fx+ x (arithmetic-shift x -8))))
(let ((x (fx+ x (arithmetic-shift x -16))))
(bitwise-and x #x0000003F)))))))
Turns into somewhat redundant C, looks much like transliterated bytecode, e.g. long v17 = 0;
// ...
// popcnt.scm:7
v17 = 0;
// ...
// popcnt.scm:7
v17 = (t37 & 252645135);
// popcount32
// popcnt.scm:8
t40 = crunch_arithmetic_shift(v17, -8);
Interesting find in the (small) crunch.h is #ifdef CRUNCH_FREESTANDING
#include <inttypes.h>
#include <stdarg.h>
#include <complex.h>
#include "crunch-environment.h"
#else
// loads of stuff
though I haven't found crunch-environment.h in the source yet> <install location>/bin/chicken-install -test crunch
Edit: That's because this is an "egg", which is an external library/package not part of the core chicken install