Zuo: A Tiny Racket for Scripting
github.com
github.com
> As in Non-recursive Make Considered Harmful: Build Systems at Scale, we can build a better make. This commit mostly imitates Shake as described there, but in a Racket style and called "Zuo" (based on the Chinese word for "make"). The Zuo implementation started at https://github.com/mflatt/zuo, but here it's in the intended long-term home, racket/src/zuo.
> The goal is for Racket to be be just as easy for end-users to build as now after converting scripts from make and /bin/sh to zuo. So, make should work in Racket's top-level directory, and configure plus make plus make install should work in a source directory or distribution, all with no new pre-installed packages required. The new makefiles will be small, however, just ensuring that the zuo executable is built and then handing off to Zuo scripts.
* it can be linked statically, thus it should run on any Linux with a simple copy; (not by default, use `LDFLAGS=-static`;)
* it can embed in the binary the core library (and other libraries of choice), thus there is no need for other files to be installed; (this is not by default, but by using the `image.zuo` directly one can get this;)
* it has minimal startup latency, almost 2x lower than Python2.7, and many times less than Python3.10; (this is without the extra libraries embedded, with the extra libraries embedded it's still faster than Python2.7, but not by that a large of a margin;)
I haven't yet checked the available API, but it does seem to be quite enough for simple system related scripting.
But while I'm interested, I can't find any docs for what's included. For scripting, I think I would at least need the following in the standard library, no package management required:
1. A good API for filesystem ops, such as reading and writing files. Ex: reading the lines of a file into a list, writing a list to a file as lines etc.
2. Making network requests easily, with persistent connections if you need it. (see Net::HTTP in Ruby, which has become extremely usable for all but the most advanced use cases)
3. Parsing JSON at the very least, with YAML and CSV being good to haves.
4. An easy way to run shell commands for stuff that's just better handled there. (like `` in Ruby)
In addition, if the stdout natively supports colouring text that would be super sweet, but that's not a hard requirement.
I can see 1) to some extent in the examples, but without a docs site I'm not sure about the rest. Does anybody here know for sure? Otherwise, is there some other lisp that would meet these requirements?
Why: Python can be verbose, and when I want to write a one-off script to rename some thumbnails in a directory somewhere, that verbosity doesn't help. The strong typing, while good for correctness, also doesn't help much in this use case.
What I tried: V, Nim, Clojure, Scala 2, Scala 3, GNU Smalltalk, Rust, Zig, Clojure, Racket, Emacs Lisp, Raku, Ruby, OCaml, and LiveScript.
Why Raku[1]: expressive power is insane. My test case of writing a script to merge requirement versions coming from two differently formatted files needed ~30 lines of code on average, while Raku needed just 10. The next best was LiveScript with 23 lines, then Elisp with 25 (counting imports; I have all the libraries already imported in an Emacs session, so I could go down to 19 lines, but thought that would be cheating).
The language being "write-only" is not important to my use case, but I also don't feel like Raku is write-only. Yes, reading something like this:
my @toml = "script.toml".IO.lines.grep(none "" | /^'#'/).map:{S/'='.*$//.trim};
can take some getting used to, but it's not really much worse than BASH.[1] https://docs.raku.org/language/faq#Why_should_I_learn_Raku?_...?
As for that line, maybe it's my Ruby heritage, but I didn't find it particularly unreadable! Chaining messages is pretty tight and very useful for one liners.
> maybe it's my Ruby heritage
Definitely :-) My Python-only colleagues screamed in horror after seeing that line...
[1] https://rash-lang.org/ - I have a similar project running on GNU Smalltalk, but didn't get to work on it in half a year :(
Regular racket has all of the things, and if easy interaction with the shell is what you desire, you might try RASH, the Racket Shell DSL.
The last update was in 2006, but it's (in)famous for the acknowledgements section written by Olin Shivers.
Who should I thank? My so-called ``colleagues,'' who laugh at me behind my back, all the while becoming famous on *my* work? My worthless graduate students, whose computer skills appear to be limited to downloading bitmaps off of netnews? My parents, who are still waiting for me to quit ``fooling around with computers,'' go to med school, and become a radiologist? My department chairman, a manager who gives one new insight into and sympathy for disgruntled postal workers?
My God, no one could blame me—no one!—if I went off the edge and just lost it completely one day. I couldn't get through the day as it is without the Prozac and Jack Daniels I keep on the shelf, behind my Tops-20 JSYS manuals. I start getting the shakes real bad around 10am, right before my advisor meetings. A 10 oz. Jack 'n Zac helps me get through the meetings without one of my students winding up with his severed head in a bowling-ball bag. They look at me funny; they think I twitch a lot. I'm not twitching. I'm controlling my impulse to snag my 9mm Sig-Sauer out from my day-pack and make a few strong points about the quality of undergraduate education in Amerika.
If I thought anyone cared, if I thought anyone would even be reading this, I'd probably make an effort to keep up appearances until the last possible moment. But no one does, and no one will. So I can pretty much say exactly what I think.
Oh, yes, the *acknowledgements*. I think not. I did it. I did it all, by myself.
https://scsh.net/docu/html/man.htmlOlin likes writing, obviously, and I suspect he started with "I did it. I did it all, by myself" and found a way to get there.
Lisp are in a great place where you can extend syntax to the problem domain. This means that you can bolt on a system like this and it feels just like home.
How feasible is it to run an arbitrary Racket application on top of this small core? (Even if all these features are implemented badly for ease-of-implementation)
Standard Scheme seems to allow a small base, but Racket has a lot of things built-in and I'm not sure how much can be done as a library vs. needing runtime support.
R7RS could totally be used to write a library that allows running any racket/base program. It's called an interpreter :D.
The nice thing about Racket is the #lang system allows you to work with many different languages in the same project. Racket has an R5RS [1], R6RS [2], and R7RS-small [3] implementation as a #lang.
[1] https://docs.racket-lang.org/r5rs/index.html
[2] https://docs.racket-lang.org/r6rs/index.html
[3] https://github.com/lexi-lambda/racket-r7rs/blob/master/READM...
All of your links are someone implementing Scheme in Racket, not Racket in Scheme. So that would make Scheme "safe", but not Racket.
It would be possible to write an interpreter in any language, but I can't tell if that would take weeks or years before it could run most racket/base programs.
Racket itself is written on top of Chez Scheme, so does that satisfy your safety condition?
Probably means "portable". If I'm reading it correctly, they want to be able to run Racket programs using a portability layer instead of writing a full interpreter. That would be something like using WINE vs. VirtualBox running Windows inside.
> Are you worried about Racket becoming unmaintained?
This is quite understandable concern, and even if it doesn't happen, having an "exit strategy" prepared is not a bad thing.
> Racket itself is written on top of Chez Scheme, so does that satisfy your safety condition?
Right, I forgot about it! After the rewrite/porting to CS Racket should have become easier to port to further platforms. I think much of Racket's reader and macro-expander was rewritten in pure Scheme.
@MichaelBurge - take a look at the blog[1] and follow links from there[2]. Racket was ported from a custom JIT-capable implementation to Chez Scheme. It took 4-5 years, but it was finished last year. The performance is now at the same level it was before, but a lot of C code is now written in Scheme.
[1] https://blog.racket-lang.org/2020/02/racket-on-chez-status.h...
[2] migration done post: https://blog.racket-lang.org/2021/01/racket-status.html
Zuo is only superficially like racket. You likely can't do any of the fancy things in it.
> The problem with the current build system could be characterized as too large a gap between C and make and the next runnable element, which is either Chez Scheme or Racket BC; neither of those are simple to build. Zuo, a tiny Racket, is an intermediate step to bridge that gap.
https://github.com/volution/vonuvoli-scheme
The main usecase for this was exactly scripting and systems-programming in Scheme.