Chicken Scheme
call-cc.org
call-cc.org
It's pretty amazing that it works, particularly in relatively portable C. Also gets fairly decent performance, too: as Schemes go Chicken is one of the faster ones.
https://www.more-magic.net/posts/internals-gc.html
https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54....
If you believe ecraven's benchmarks it's pretty exactly middle of the pack. Chez Scheme, Racket, Gerbil, MIT, Bigloo Guile, Loko, Cyclone, and Bones all are more performant.
And the ones where it does better are almost all not very popular implementations.
I think its speed is totally fine and I like the language and community but I don't think it's relatively fast among Schemes.
Chicken’s last generation GC might be mark-sweep, but that isn’t the MTA part.
And the continuations are only cheap in the chicken context. Other schemes with other GC strategies have continuations with a large overhead, but still manage to be faster than chicken in benchmarks that are very continuation heavy.
Chicken is a very nice scheme, with probably the nicest Devs of any open source project, but cheney on the MTA is not magic by any stretch.
> A Cheney queue is a garbage collection scheme originally described by J. C. Cheney. The MTA is a reference to a song recorded by The Kingston Trio.
nix-shell -p chicken --run csi
for one-off invocationor alternatively, tweak the package to rename them:
chicken = pkgs.chicken.overrideAttrs (attrs: {
postInstall = attrs.postInstall + "\n" + "mv $out/bin/{csi,chicken-csi}
})Generally, it's just a bunch of JS, C#, Java, Python, and some Scala that runs everywhere I look, which often also has a large "I came across it and I got to work" type of developer or engineer using it. Maybe it's just the type of ecosystem I keep hopping around it but it seems that it's much less prominent than you'd expect.
There are always novel compilers, transpilers and showcases, but the amount of widespread use eludes me. (Only ErLang comes to mind with RabbitMQ, and maybe OCaml with Xen)
Chicken Scheme was the specific implementation I started with too. I always found it fast/solid and saw no reason to switch. The abstractness of Lisp and the direct access to memory/C FFI were a nice mix. It suited my interest in music, where composition and DSP fell into those two respective domains.
I don't have an appetite for dynamic languages these days, but I might still reach for Chicken if I had to put together a dozen line script or something.
I poked around Lisp, very casually, for many years. But early on I really struggled with `lambda`.
It was a meaningless word to me. The classic complaints with CAR and CDR et al didn't help. More meaningless words.
Finally, I managed to stumble across the book "Simply Scheme". And the first thing it did was rename everything. It didn't take long to realize that `lambda` was a function. And then, the light clicked on.
"Oh."
During my learning of computer concepts, etc. there were a few events of true "epiphany", and learning what lambda really was, and how it worked, closures, that was one of them.
The secret for picking it up is to just use it.
Not for some huge project, not for bolting together a bunch of pre-built libraries. But for some actual processing. Something that needs little more than to read some file, do something to it, and write it back out. Baby steps.
And, certainly, don't get intimidated by the development environments. I use emacs for my work simply because it paren matches and auto-indents. All of the integration, I don't bother with. My projects aren't that big. A few thousand lines of code. I'm spoiled by auto-indent (and re-indent), so that's my crutch.
The key point being it takes very little to get started.
Working the problems in Little Schemer is fun. Doing SICP exercises is fun. On Lisp is an inspiring, opinionated book, and fun to read because of it. So, you can start there.
Go "write Fortran in Lisp", as they say. All of the stuff about macros and lambdas and functional or not etc. doesn't do you much good when you're searching and staring at an 8 page document on LOOP. Just write some simple stuff to get familiar with the things every piece of code has to do: input data, calculate on it, iterate on it, and print it out. Looking up the stuff that's muscle memory for your other languages kills momentum and motivation. So, work some simple stuff first. Write some crummy code first, then work on idiomatic code. Work on using new concepts later.
For me, I can remember:
- objects are closures and closures are objects - properly getting the JS asynchrony model - pointers and the whole memory addressing model - HTTP being stateless
I must have had an early epiphany with function return values, since I remember not writing functions correctly at first, but I don’t remember the actual epiphany.
I think realizing that execution in imperative languages was one after the other and that there's a sort of "cursor" that goes through the code (execution flow/instruction pointer/whatever) was one of the first things that made things click.
I miss them, as they were incredibly endorphin-releasing moments.
But I must admit, the day I saw a guy run, essentially, "cpio ... | rsh otherhost cat > /dev/tape", that was a very "aha" moment in terms of overall system design and what networking brought to the table.
I dont find them useful commercially YMMV but I do think they stretch the way you program and I actually enjoy them more. Prolog is my favourite.
Their history is tied to academic / research and concepts but it's not necessarily a barrier.. if you like hacking, and learning you'll find pleasure there too. Also a lot of what you're using these days have been pioneered in these fields so you might connect both past and present nicely.
From there I learned how easy it was to make your own Lisp and learned a lot about how programming languages work and had a lot fun with that for a while.
Example SXML template, that fills in data fields from a given namespace:
(form
(@ (method (%data form-method))
(action (%data form-action)))
(label "Username")
(input (@ (type "text")
(name (%data username-input-name))))
(label "Password")
(input (@ (type "password")
(name (%data password-input-name))))
(input (@ (type "submit"))))https://github.com/dgoffredo/dgoffredo.github.io/blob/372300...
You could do the exact same thing in javascript.
Incredibly useful.
And then there is the whole SXPATH and SXSLT stuff that makes sxml a lot nicer than HTML.
Hardly had to touch it, it's brilliant.
As an outsider (I admire Scheme, but don't really use it day to day), I got the impression R6RS was very divisive. Some people really wanted to make a "batteries included" revision to the standard so that Scheme could be used the way Python/Java is. However, this meant that the standard was prohibitively complicated for small/research implementations, and it lost some of the R5RS elegance and philosophy. In response, R7RS tried to tie things back together by having two versions (I think they call them Small and Large), where Small is a subset of Large, and both pretty much disregard R6RS.
Anyways, I believe Chicken was firmly in the "disagrees with the design of R6RS" camp. And for what it's worth, I think the decision to create the name "Racket" (and associated design changes) also came about because of this schism. Even though they have an R6RS language/implementation, I don't believe the Racket language conforms to any of the RnRS standards.
I'm certain someone here can do the history more justice if they wanted.
1) R6RS isn't really all that "batteries included", though it has some really basic features like hash tables that weren't in R5RS (but were in most Schemes anyway). The emphasis was on portability and safety. All R6RS implementations, if they don't have bugs, behave the same as all the rest at least as far as the standard extends, and the standard defines pretty closely what arguments are accepted, what values are returned, and what exceptions are signaled (the last was controversial even within the closed R6RS committee).
What wasn't considered was interoperability with common practice in other Schemes. In pursuit of this, R7RS favors interoperability over portability: the standard is less constraining, which makes it easier to integrate with existing Schemes. So R6RS hashtables (things that can be hashted, eh?) are incompatible at the procedure name level and some of the semantics with almost everybody else's hash tables. R7RS-large made them as compatible as possible. (Granted, we took more time to think about it.) R7RS-large also favors big-enough-ism over minimalism within each library, though it won't have as many libraries as people from other languages might like.
2) The current plan for R7RS-large will provide many parts of R6RS (a little bit R7RS-ified in some cases), provided they are voted in by the R7RS-large working group.
3) The rename of PLT Scheme to Racket had nothing to do with RnRS. PLT supported R6RS before and supports it R6RS today, though its use is not particularly encouraged by the Racketeers, who want you to use their own main dialect of Scheme, also called Racket. The change had more to do with PLT's multilingual capabilities: it supports many dialects of Scheme plus completely non-Scheme languages like Python and Algol 60, and it would be straightforward, if tedious, to provide Fortran, Cobol, and even C. In addition, PLT had no real link with the various university programming-language theory groups any more.
On participating in the Working Group:
Any Schemer can join the Working Group at any time: subscribe to scheme-reports-wg2@googlegroups.com and listen for CFVs. (If you have never voted before on anything Scheme-related, send a message after you subscribe giving your name, a little bit about yourself, and a bit more about your interest in Scheme. This is primarily to discourage sockpuppets.) There are long spells of inactivity followed by intense discussion when a new ballot comes up. All discussions and votes are public. Behind-the-scenes work is also done in public using the SRFI process at srfi.schemers.org, which produces specs and sample
Couldn't even count on Python 2 being there. It was either POSIX shell or statically linked native, and Chicken (with a few modifications) allowed me to do that on all of the above platforms.
Fortunately (in retrospect), none of my code ever found much use. Learned a lot about Scheme, though :)
And yes, I think that "The Revised Revised Revised Revised Revised Revised Revised Report on the Algorithmic Language Scheme" is pushing the joke rather too far, but R⁷RS is what name got consensus. It's modeled on "The {,Revised|Modified} Report on the Algorithmic Language Algol 60", where the usual abbreviations were R, RR, MR, but I like to write R⁰RA60, R¹A60, R²RA60 instead. Ditto with R⁰RA68, R¹A68 for the distinct language Algol 68. Finally, the incomplete report on the Scheme offshoot Kernel is R⁻¹RK.
I would say the reason it beats Chicken and Gambit is that it has a Scheme-specific compiler to machine code that has been worked on for a long time with performance in mind.
Dybvig's talk on Macro Writers' Bill of Rights explains some of the optimizations Chez does: https://www.youtube.com/watch?v=LIEX3tUliHw (Why macro writers? Because the compiler will handle superfluous generated code so macros doesn't have to)
See also The Development of Chez Scheme for the history of it: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72....
I'd guess if you're sure your `fib` function handles only integers, you should get a lot of easy inlining/specialization at your disposition.
Chez instead provides typed/unchecked arithmetic functions, like fx+, flround and so on. In my experience, those sometimes make a big impact on performance(though realistically in some of those cases it would be better to ask C to do it for you).
Racket similarly makes it possible to do either.
Edwin Brady (Idris 2 creator and main author) has mentioned a few times that Chez is surprisingly and impressively fast.
Show HN: How I used Chicken Scheme to build registromat.com - https://news.ycombinator.com/item?id=23860977 - July 2020 (4 comments)
Chicken Scheme 5.1 - https://news.ycombinator.com/item?id=20259324 - June 2019 (21 comments)
Making Games in Lisp with Hypergiant and Chicken Scheme - https://news.ycombinator.com/item?id=18647562 - Dec 2018 (22 comments)
Chicken Scheme 5.0 - https://news.ycombinator.com/item?id=18402567 - Nov 2018 (86 comments)
Ugarit: content-addressable storage and backup written in Chicken scheme - https://news.ycombinator.com/item?id=14637593 - June 2017 (11 comments)
Chicken Scheme - https://news.ycombinator.com/item?id=12773314 - Oct 2016 (31 comments)
Let's add a statistical profiler to Chicken Scheme - https://news.ycombinator.com/item?id=11097044 - Feb 2016 (3 comments)
Making Games in Chicken Scheme with Hypergiant - https://news.ycombinator.com/item?id=8850722 - Jan 2015 (4 comments)
Chicken Scheme Websockets - https://news.ycombinator.com/item?id=8534082 - Oct 2014 (20 comments)
Chicken Scheme internals: the garbage collector - https://news.ycombinator.com/item?id=7499101 - March 2014 (25 comments)
Example Project Using Chicken Scheme on Android - https://news.ycombinator.com/item?id=6399148 - Sept 2013 (7 comments)
Embed the Chicken Scheme runtime into a FastCGI module hosted by Apache server - https://news.ycombinator.com/item?id=5733388 - May 2013 (3 comments)
Developing database-driven web applications with Chicken Scheme - https://news.ycombinator.com/item?id=5692190 - May 2013 (5 comments)
Behind the Scenes with Chicken Scheme - https://news.ycombinator.com/item?id=5644349 - May 2013 (22 comments)
Chicken Scheme - https://news.ycombinator.com/item?id=5380513 - March 2013 (61 comments)
How Chicken Scheme compiles to C - https://news.ycombinator.com/item?id=3440777 - Jan 2012 (9 comments)
Chicken - Portable, Efficient C Compiler for the Scheme Programming Language - https://news.ycombinator.com/item?id=2278562 - March 2011 (13 comments)
Chicken Scheme looks mighty fine - https://news.ycombinator.com/item?id=2241015 - Feb 2011 (15 comments)
How do I start with Scheme and the moder R7RS standard?
Books, tutorials, courses ?
Thank you.
We built a server backend using Chicken in six months, it held up under significant load, and as normal the database connection was where we had to put most of the engineering effort.
We used a few macros to remove overhead in a few places where you'd use generic functions, and that saved us a little performance.
All in all - I'd happily use it in production again. I like it when the tech stack is boring and does what is expected of it.
Just about everything out there will have decent Scheme support. It's a lisp, and it's a well-defined lisp. Scheme being well-specified makes everything simple. (Even the SRFIs are well specified.)
Our deploys were via Jenkins, but through Chicken's egg system it wasn't exactly a complicated process.
I hear a lot about “repl-driven” development with Clojure and CL, but anytime I get experimental with it I find myself neck-deep in editor configuration, or simply wrestling with emacs keybindings.
Because load was a primary concern, we mostly used a test-driven cycle where we'd spin up the server and then attempt to DOS it for every change. Not something you want happening much on your dev machine.
However, for the simpler tests, if the test system hit a failure, it would then drop into a REPL (not on the production server). So it was sort of like a nicer debugger.
The test system was developed in-house, but if I remember, it was something like a 100 lines of code. That's one of the things that Scheme guides you towards - if you don't have a wheel, it's generally five minutes to make one.
I wouldn't generally bother fighting with emacs or configuration for anything. If you're fighting your tools, you're not being productive. Fine to do if you're not being paid, not so fine in a workplace. Keep things simple, and you'll do better than if you try and be clever. Rainbow braces and documentation lookup will get you 99% of the way to where you want to be.
That being said, one of our devs wrote their code with Wisp (SRFI-119), and had a git pre-commit hook that automatically rewrote it back to normal Scheme, and another hook in their editor to turn it into Wisp code when they opened a file. Nobody noticed for over a month.
Scheme makes it easy to write the way that you want to, using the tools that you like.
For others like me who are curious, here's what Wisp looks like:
Wisp (SRFI-119) Simpler, indentation-sensitive Scheme - https://srfi.schemers.org/srfi-119/srfi-119.html
Discovering this philosophical division was a bit surprising to me when I first started talking to Lispers outside of my CL bubble.
When I get more free time I'm definitely eager to jump back to Guile programming. But on my first test drive, I definitely had good experience with the repl driven approach. No matter how barebones of a setup it is, it's better than my past Haskell repl experience, where it almost felt like a tool you need to use no matter what.
In the past, I've got quite far with two simple functions:
(define (e) (system "vi test.scm")) (define (l) (load "test.scm"))
and just rinse and repeat using those.
Don't let tooling get in your way.
In the end, what we ended up with was our own library written around libevent, which could interface with awful's plugins. As a bonus, it was much, much faster than awful. It even beat out nginx in some situations.
The Chicken compiler actually compiles down to C, which has the nice side-effect that you can easily include literal C code. Here's an example: https://www.more-magic.net/posts/scheme-c-integration.html
I found the documentation to be good. I remember looking at it and finding whatever I was looking for, thinking: "It's all here!" Even stuff, that I do not fully understand like CK-macros (http://wiki.call-cc.org/eggref/5/ck-macros).
There was one issue though, which stopped my hobby project: Support for UTF-8 in display seems to be broken: http://bugs.call-cc.org/ticket/1374 As I tried to build a vocabulary trainer, I had to switch to another Scheme.
The web framework called "awful" (http://wiki.call-cc.org/eggref/5/awful#description) seemed nice too.
This reply is a bit late because someone pointed me at it and suggested it was worth answering. ...so I hope that this is useful!
I have experience using Chicken Scheme in production both on knodium.com and registers.app
Both times it has gone well.
There's an HTTP implementation ( https://api.call-cc.org/5/doc/intarweb ), a webserver (https://api.call-cc.org/5/doc/spiffy that supports SSL) and an HTTP client ( https://api.call-cc.org/5/doc/http-client ). There's also an "app server" that tries to be like other app servers you might already know ( https://api.call-cc.org/5/doc/awful ).
We had to write a lot of our own stuff but it fits fairly neatly into the scheme-way of doing things: you can get a remarkable amount done with just a few simple lines of code.
I'd probably want to write about as much in any other language as a lot of what we built were domain level abstractions.
Knodium is now long gone but there's a video of what it looked like here: https://www.youtube.com/watch?v=gOPuWi-dbQg
We had a very talented web designer and we also built a "Widgets and forms" toolkit. I gave a talk at FrOSCon quite early in the development and it was saved for posterity: https://media.ccc.de/v/c116_lisp_-_2013-08-25_11:15_-_buildi... The first few minutes of audio are broken but it sorts itself out.
I built a bunch of things along the way and released as many of them as I could as open source: http://wiki.call-cc.org/users/andyjpb
We're currently doing https://registers.app with a similar stack so I'd be pleased to talk more if anyone has any questions.
John knows already, but the Scheme were meant to be called Schemer, but the file system only had 6 characters in the filenames.
Apropos, the suffix "bit" is popular too: rabbit, orbit, gambit, picbit, twobit