Hacker News new | ask | show | jobs
by joeatwork 1107 days ago
If this project interests you but is a bit more minimal than you need, the Janet language is a slightly-less but still pretty lightweight embeddable Lisp with a strong library and community: https://janet-lang.org/
3 comments

Has anyone here switched from Common Lisp or Scheme/Racket to Janet? If so, what was good/bad about the switch? Or was it just different?

I recently started learning Common Lisp, and it’s been mostly great, but my two complaints are 1) memory usage and 2) deployment (copy source or distribute a relatively huge world image—and I haven’t found any way to get a fully static build without patches, even with ECL).

Janet could solve both of those, although I’d pay a performance penalty due to it being interpreted, and I assume there are a lot fewer libraries/tools. I really like the idea of a Lua-sized Lisp, but I’m not sure if I should jump ship from a traditional Lisp yet.

I’ve never done basically any lisp except a toy project but this

> distribute a relatively huge world image

in my understanding of the lisp world is actually a feature…?

You’re right, it is a feature, but I’d like the option to distribute a smaller binary without everything built in. Roswell supposedly helps with this, but I haven’t gotten it to work yet. Some commercial implementations support this, I think, but they’re priced well beyond my hobby project budget.

Janet is intriguing to me because it has a small footprint (even smaller than most Schemes). I’ve heard it’s handy for building little utilities, especially if you want someone else to be able to run them (a situation I find myself in regularly).

To provide a some extra context for other readers and mostly respond to the GP:

Janet does not do any stripping for distribution -- Janet images compiled to native executables still contain the full compiler/stdlib/runtime/everything in <1mb.

Janet is planned and built as an embeddable language; CL is not.
Absolutely, but it’s not even embedding that I had in mind. I want to be able to produce fully statically linked binaries, because in my experience that is the only truly portable binary solution on Linux. It’s a trade off for sure, but it’s something I’ve found useful for running on e.g. Raspberry Pi.

For SBCL, the two main approaches I’ve seen are: a) use a patched version of SBCL that is statically linked or b) build against an old glibc and hope for the best (which sadly doesn’t work on my musl libc-based distribution). I guess the third approach is distribute source and compile on the device—this is what I’m actually doing, but it seems a little silly to recompile every time, even if it’s the same architecture.

And keep in mind this is just my wishlist of functionality. It’s not necessary and I don’t expect it, but it would be really convenient.

easiest solution I found was building SBCL targetting an old glibc using zig as the c compiler:

CC="zig cc -target x86_64-linux-gnu.2.28" LD="zig cc -target x86_64-linux-gnu.2.28"

zig bundles in all the glibc headers, so I think it should build on musl libc-based distro

for more complicated programs with native dependencies there is (https://github.com/Shinmera/deploy) or guix has a lot of CL libraries already and it's fairly easy to write packages for others, you can specify all dependencies with guix and use guix pack to get a .tar with all dependencies you can unpack and run on any other linux box

I was wondering if compiling via Zig would work. Also, thanks for the Guix tip—I will give that a try!

I think native dependencies would require something like this (which I believe uses Deploy to solve part of the problem): https://www.timmons.dev/posts/static-executables-with-sbcl.h...

I just started toying with Janet recently & so far it’s very pleasant
Does Janet have something like Clojure's threading (->, ->>)?
For a Lisp not to have threading macros, it would need not to have macros, period. Writing these is so trivially simple you can ask ChatGPT to do it and it would get it right on the first try.

On a related note: it would be an interesting read if someone tried tracing the threading macros to some origin point(s) in the past. There seem to be two main variations, Lisp's ->/->> and |> in many functional languages (Elixir, OCaml, Raku). The construct seems to have gotten popularized by Clojure and F#, but I don't think it was invented in either (maybe rediscovered).

It had to start at some point, somewhere, but I wasn't able to locate that point.