some other super fine Scheme implementation’s(sic) not mentioned in the article
Yeah, MIT Scheme has Edwin and a more-or-less CL-like debugging experience, Gauche has a hardware store's worth of batteries included, Loko compiles down to machine code without passing through C, Chez is fast, and Cyclone has a nice GC.
> That said, Common Lisp is weird. What I find particularly jarring is that functions and variables live in different namespaces:
Lisp-2s aren’t the only languages in which functions and variables are different namespaces - the same is true of PHP, Perl, Bash, etc. But the later mark the distinction through syntax - variables start with a dollar sign, functions don’t. I think there is something to be said for that approach, compared to the Lisp-2 way it is easier for beginners to understand, and it is instantly obvious whether a symbol is a variable or something else like a function, while also avoiding the Lisp-1 problem of built-in function names clashing with those of popular variable/argument names. I wonder why there are so few Lisp-like languages which adopt the “sigil solution”. (Common Lisp does have sigils, such as :keywords, but not for variables.)
A standard practice in Common Lisp distinguishes special variables by "earmuffs": the symbol names of special variables, by convention, start and end with asterisks. No requirement for this exists in the language definition, but just about everyone follows it.
It would be really annoying to have the same sort of de facto requirement for function names. Making the programmer use funcall or apply when calling a function value is much less intrusive, especially since CL idiomatically doesn't have the tail call fetish that Scheme seems to have.
Although Common Lisp is called Lisp-2, there are actually many more namespaces... I think I counted 5 or 6 the last time I tried. But it is pretty sensible to keep functions in a different namespace. For instance, it allows you to:
(let ((let '`(let ((let ',let))
,let)))
`(let ((let ',let)) ,let))
It's like `make make make make`. But it is nice that in CL you don't have to jump through hoops on common words that happen to be function or package names. You have a list and no meaningful name? Call it `list`:
(defun some-algo (list ...) ...)
Sure you can abuse this, everything can be abused. But I'd rather risk an asshole doing that `let` thing (which wouldn't make it past code review) than have more name collisions and naming contortions to avoid them. If the language at least warned on renaming it would be helpful, but then you get things like Go. When I was learning it I accidentally overwrote some built-in function (I don't recall which one, it wasn't actually `make` like in this demo):
package main
func main () {
make := 10
aMap := make(map[int]string) // this is now an error
}
I wish I could remember what it was, it was a reasonable name in context (unlike `make` above). But it had a similar effect and a similar strange error. The error is at the function call site, which is technically correct because you're trying to use an `int` (here) as a function. But `make` (above) and similar functions should probably get a warning emitted when you redefine them, at a minimum.
In practice it is not a footgun at all! If you use Lisp, you can tell what's a function and what's a variable by position - functions are always first in a list, variables - never, (except in bindings)... etc.
Have you seen Mezzano? It's a pure Common Lisp Operating system, albeit there are few C programs that were transpiled to CL to run on top as well (IIRC, DOOM :D)
It's somewhat limited but AFAIK it could in theory be made to self-host (right now IIRC image building is done separately from another system, but that's mostly a case of some programming work)
I feel most "at home" in Common Lisp, though I agree that Scheme is more elegant. Speaking of elegant I recently had some fun playing around with Janet (https://janet-lang.org) and I have to say it is quite nice.
If I had to pick a language to stay in forever and I had the time to really grow it into what I wanted using C extensions I'd probably choose Janet (or make my own similar lisp).
Like most people, though, I have a day job and until I decide to retire I won't have time to reinvent an entire personal programming system for myself. For pure "get in there and have fun" sessions after work Common Lisp gets my vote despite its clunkiness. And besides... it's a lisp! If something's too clunky I'll just fix it.
Janet is very similar to s7 Scheme too, a minimal scheme for embedding that borrows heavily from CL. I use s7 for Scheme for Max, the author made it for various other computer music purposes.
It's nice to see the CL ecosystem evolving. SBCL sees regular updates with new optimizations. The editor support is getting better: Vim, Atom, Sublime, VSCode… have good to very good support[0], & Jupyter notebook, the Lem editor… and a new lisper started a CL editor based on Tauri: Parrot https://github.com/fonol/parrot. Cool projects emerge (lisp-stats , the Sento / cl-gserver actors library, the Kons-9 3D graphics library, the CLOG web-gui…)
> 50MB
With compression (zstd now), SBCL binaries weigh ±25MB. Start-up time is super fast. I built a standalone binary for my web app, it is straightforward to start it on the background and access it from an Electron window.
If you want to do something like what the article is describing with Guile, but without the GPL constraints, you might like s7 Scheme. It's a bit like a cross between Guile and Janet, with CL macros, keywords, and first class environments. I use it for Scheme for Max, an extension to the Max/MSP computer music platform allowing one to script Max in Scheme. It's BSD licensed.
Also, the author Bill is very helpful on the mailing list.
27 comments
[ 3.9 ms ] story [ 115 ms ] threadNot mentioned: Hy (hylang) that adds Clojure-like syntax to Python, and some other super fine Scheme implementation’s not mentioned in the article.
Yeah, MIT Scheme has Edwin and a more-or-less CL-like debugging experience, Gauche has a hardware store's worth of batteries included, Loko compiles down to machine code without passing through C, Chez is fast, and Cyclone has a nice GC.
Same with REPL functionality. Same with libraries available.
Lisp-2s aren’t the only languages in which functions and variables are different namespaces - the same is true of PHP, Perl, Bash, etc. But the later mark the distinction through syntax - variables start with a dollar sign, functions don’t. I think there is something to be said for that approach, compared to the Lisp-2 way it is easier for beginners to understand, and it is instantly obvious whether a symbol is a variable or something else like a function, while also avoiding the Lisp-1 problem of built-in function names clashing with those of popular variable/argument names. I wonder why there are so few Lisp-like languages which adopt the “sigil solution”. (Common Lisp does have sigils, such as :keywords, but not for variables.)
It would be really annoying to have the same sort of de facto requirement for function names. Making the programmer use funcall or apply when calling a function value is much less intrusive, especially since CL idiomatically doesn't have the tail call fetish that Scheme seems to have.
I mean, yes, having functions in a different namespace may be sensible, or at least defensible. That example is ridiculous.
In seriousness I like the ability to make such distinctions even if it can be a huge footgun.
But in Lisp/Scheme? Preferrably no C. Just Lisp/Scheme and assembly.
It's somewhat limited but AFAIK it could in theory be made to self-host (right now IIRC image building is done separately from another system, but that's mostly a case of some programming work)
If I had to pick a language to stay in forever and I had the time to really grow it into what I wanted using C extensions I'd probably choose Janet (or make my own similar lisp).
Like most people, though, I have a day job and until I decide to retire I won't have time to reinvent an entire personal programming system for myself. For pure "get in there and have fun" sessions after work Common Lisp gets my vote despite its clunkiness. And besides... it's a lisp! If something's too clunky I'll just fix it.
> 50MB
With compression (zstd now), SBCL binaries weigh ±25MB. Start-up time is super fast. I built a standalone binary for my web app, it is straightforward to start it on the background and access it from an Electron window.
[0]: https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
[1]: https://github.com/Lisp-Stat/lisp-stat/
[2]: https://github.com/mdbergmann/cl-gserver
Also, the author Bill is very helpful on the mailing list.
s7: https://ccrma.stanford.edu/software/snd/snd/s7.html Scheme for Max: https://github.com/iainctduncan/scheme-for-max