<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Planet Scheme</title><link href="https://planet.scheme.org/" rel="alternate"/><link href="https://planet.scheme.org/atom.xml" rel="self" type="application/atom+xml"/><id>https://planet.scheme.org/</id><updated>2026-05-14T16:00:53Z</updated><entry><title>Scheme Requests for Implementation: SRFI 272: Pretty Printing</title><link href="https://srfi.schemers.org/srfi-272/" rel="alternate"/><id>https://srfi.schemers.org/srfi-272/</id><updated>2026-05-13T12:00:00-08:00</updated><author><name>Sergei Egorov</name></author><content type="html">SRFI 272 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
  This SRFI follows the traditional Scheme model of pretty printing, which treats it as a 
  process distinct from general controlled formatting. While general-purpose formatters 
  often prioritize specialized presentation at the expense of machine-readability, Scheme’s 
  pretty-printers (such as those of SLIB and MIT Scheme) have traditionally treated 
  pretty printing as a variant of &lt;code&gt;write&lt;/code&gt;, differing primarily in the insertion 
  of whitespace to make the presentation more palatable to humans. Common Lisp’s pretty-printer, 
  by contrast, fills two roles simultaneously by integrating pretty printing with both its 
  format facility and its generalized &lt;code&gt;write&lt;/code&gt; procedures. This unified approach 
  offers great power, but at the cost of complexity that can make it difficult to use effectively.

  We propose a specialized, layered approach, specifying five libraries of increasing functionality, 
  where all but the first are optional. The libraries are downward-compatible: more powerful libraries 
  satisfy all requirements of the simpler ones while adding new features. Implementors may 
  choose to support a maximum level of functionality appropriate for their systems. Integration with
  monadic and string-based formatting libraries is supported.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>spritely.institute: Hoot 0.9.0 released!</title><link href="https://spritely.institute/news/hoot-0-9-0-released.html" rel="alternate"/><id>https://spritely.institute/news/hoot-0-9-0-released.html</id><updated>2026-05-13T12:00:00Z</updated><author><name>Dave Thompson</name></author><content type="html">&lt;p&gt;We are excited to announce the release of &lt;a href=&quot;/hoot&quot;&gt;Hoot&lt;/a&gt; 0.9.0!  Hoot
is a Scheme to WebAssembly compiler backend for
&lt;a href=&quot;https://gnu.org/software/guile&quot;&gt;Guile&lt;/a&gt;, as well as a general purpose
WebAssembly toolchain.  In other words, &lt;em&gt;Scheme in the browser!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This release contains new features and bug fixes and since the &lt;a href=&quot;/news/hoot-0-8-0-released.html&quot;&gt;0.8.0
release&lt;/a&gt; back in February.&lt;/p&gt;
&lt;h2&gt;Use Hoot in the upcoming Lisp Game Jam!&lt;/h2&gt;
&lt;p&gt;On Friday (May 15th 2026), the &lt;a href=&quot;https://itch.io/jam/spring-lisp-game-jam-2026&quot;&gt;Spring edition of the Lisp Game
Jam&lt;/a&gt; will begin!  It's
a 10-day long game jam where participants make games using their
favorite flavor of Lisp.&lt;/p&gt;
&lt;p&gt;Does making a small web game in Scheme using Hoot sound appealing to
you?  Well, then we have just the thing to get you started: the &lt;a href=&quot;https://codeberg.org/spritely/hoot-game-jam-template&quot;&gt;Hoot
game jam
template!&lt;/a&gt; This
template project has everything you need to start making an HTML5 game
with Hoot quickly.&lt;/p&gt;
&lt;p&gt;The template repository includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bindings to the necessary web APIs to make an interactive game with
HTML5 canvas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Makefile for compiling, running a development web server, and
generating a .zip bundle for uploading to itch.io&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A very simple Breakout-like example game that demonstrates how to
put all the pieces together&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to contributor Gonzalo Delgado, the game jam template now
features gamepad input support!&lt;/p&gt;
&lt;p&gt;For more inspiration, here are some games made with Hoot for past
jams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://davexunit.itch.io/cirkoban&quot;&gt;Cirkoban&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://davexunit.itch.io/strigoform&quot;&gt;Strigoform&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://podatus.itch.io/shields-tyvm&quot;&gt;Shields TYVM&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, onto the release notes!&lt;/p&gt;
&lt;h2&gt;Toolchain changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Added the concept of host provided types.  Useful for Hoot on
Wastrel support.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switched from legacy exceptions to standard Wasm exceptions, which
were officially adopted in July 2025 but have been available in
browsers for much longer.  The &lt;code&gt;--experimetal-wasm-exnref&lt;/code&gt; flag is
passed to NodeJS in case it is old enough to still require this
feature flag (which is currently the case for Guix).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added support for DWARF custom section.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Compiler changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Replaced function name/source metadata with DWARF.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Changed default debug level to 1, which now includes emitting DWARF.
For a production build stripped of all debug data, use debug level 0
(&lt;code&gt;-g0&lt;/code&gt; in the CLI) or strip the binary afterwards using &lt;code&gt;hoot strip&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update compiler backend for new primitive bytevector predicates
introduced in Guile 3.0.11.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added support for bitvector literals on big endian host systems.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Runtime changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Floating point number to string conversion is now implemented in
Scheme rather than relying on an import.  This makes binaries
slightly bigger but makes it easier to support Hoot on Wastrel and
non-JavaScript runtimes generally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bignum imports have been monomorphized to ease non-JavaScript
runtimes (Wastrel, again).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scheme binaries now export a &lt;code&gt;main&lt;/code&gt; function that takes 0 arguments
and returns 0 values that invokes the internal &lt;code&gt;$load&lt;/code&gt; function.
This makes it posible for Wastrel to boot a Hoot program without
support for the Scheme reflection interface.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added DWARF parser to &lt;code&gt;reflect.js&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Removed &lt;code&gt;fsqrt&lt;/code&gt; import in favor of using &lt;code&gt;f64.sqrt&lt;/code&gt; instruction.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Scheme changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Range errors now include the range in the exception irritants list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added &lt;code&gt;uint8array-&amp;gt;bytevector&lt;/code&gt; procedure to &lt;code&gt;(hoot typed-arrays)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vectors are now considered self-evaluating in &lt;code&gt;(hoot expander)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added internal &lt;code&gt;(hoot module-syntax)&lt;/code&gt; module to gather runtime
module macros and support code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;define-record-type&lt;/code&gt; now works in the Scheme interpreter for record
types with up to 8 fields.  (Supporting more than 8 fields is
planned but will require larger changes to the Hoot runtime.)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CLI changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;guild compile-wasm&lt;/code&gt; has been deprecated in favor of the new &lt;code&gt;hoot compile&lt;/code&gt; subcommand.  Both commands accept the same flags.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added &lt;code&gt;hoot help&lt;/code&gt; subcommand.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Added &lt;code&gt;hoot strip&lt;/code&gt; subcommand to remove debugging information from a
Wasm binary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Feature flags have been split out from debug options in &lt;code&gt;hoot compile&lt;/code&gt;/&lt;code&gt;guild compile-wasm&lt;/code&gt;.  For example, &lt;code&gt;-gruntime-modules&lt;/code&gt; is
no longer valid; use &lt;code&gt;-fruntime-modules&lt;/code&gt; instead.  The &lt;code&gt;-g&lt;/code&gt; flag now
exclusively handles debugging data such as whether to emit DWARF or
a names section.  The &lt;code&gt;-f&lt;/code&gt; flag handles things that change program
behavior such as whether to include a runtime module system for use
with the Scheme interpreter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Documentation changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Updated manual to use &lt;code&gt;hoot compile&lt;/code&gt; instead of &lt;code&gt;guild compile-wasm&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;hoot compile --bundle&lt;/code&gt; is now recommended in web deployment section
rather than manually copying support files.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Bug fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;repl.js&lt;/code&gt; file missing from 0.8.0 (which broke &lt;code&gt;hoot repl&lt;/code&gt;) is
now included in the release tarball.  Apologies for the oversight!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed pathologically large function emitted by &lt;code&gt;lower-globals&lt;/code&gt;,
which Wasm engines such as Wastrel can struggle with.  Instead, many
smaller functions are emitted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;hash-set!&lt;/code&gt;, &lt;code&gt;hashq-set!&lt;/code&gt;, etc. now return the passed value.  This
matches Guile's behavior and allows more existing Guile programs to
work as expected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed bug in parsing zero-length custom sections in Wasm binaries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed validation of &lt;code&gt;return_call_indirect&lt;/code&gt; instruction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed missing EOF handler in REPL meta-command reader.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Browser compatibility&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Compatible with Safari 26 or later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compatible with Firefox 121 or later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compatible with Chrome 119 or later.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Get Hoot&lt;/h2&gt;
&lt;p&gt;Hoot is available in GNU Guix:&lt;/p&gt;
&lt;pre&gt;&lt;code infostring=&quot;&quot;&gt;$ guix pull
$ guix install guile guile-hoot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, Hoot is now available in
&lt;a href=&quot;https://tracker.debian.org/pkg/guile-hoot&quot;&gt;Debian&lt;/a&gt;, though it will
take awhile for this release to make it there.&lt;/p&gt;
&lt;p&gt;Otherwise, Hoot can be built from source via our release tarball.  See
the &lt;a href=&quot;/hoot&quot;&gt;Hoot homepage&lt;/a&gt; for a download link and GPG signature.&lt;/p&gt;
&lt;p&gt;Documentation for Hoot 0.9.0, including build instructions, can be
found
&lt;a href=&quot;https://spritely.institute/files/docs/guile-hoot/0.9.0/index.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Get in touch&lt;/h2&gt;
&lt;p&gt;For bug reports, pull requests, or just to follow along with
development, check out the &lt;a href=&quot;https://codeberg.org/spritely/hoot&quot;&gt;Hoot project on
Codeberg&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you build something cool with Hoot, let us know on our &lt;a href=&quot;https://community.spritely.institute&quot;&gt;community
forum&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Thanks to our supporters&lt;/h2&gt;
&lt;p&gt;Your support makes our work possible!  If you like what we do, please
consider &lt;a href=&quot;/donate&quot;&gt;becoming a Spritely supporter today&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;Diamond tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Aeva Palecek&lt;/li&gt;
&lt;li&gt;David Anderson&lt;/li&gt;
&lt;li&gt;Holmes Wilson&lt;/li&gt;
&lt;li&gt;Jonathan Frederickson&lt;/li&gt;
&lt;li&gt;Lassi Kiuru&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Gold tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Alex Sassmannshausen&lt;/li&gt;
&lt;li&gt;Juan Lizarraga Cubillos&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Silver tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Austin Robinson&lt;/li&gt;
&lt;li&gt;Brit Butler&lt;/li&gt;
&lt;li&gt;Charlie McMackin&lt;/li&gt;
&lt;li&gt;Dan Connolly&lt;/li&gt;
&lt;li&gt;Deb Nicholson&lt;/li&gt;
&lt;li&gt;Eric Bavier&lt;/li&gt;
&lt;li&gt;Eric Schultz&lt;/li&gt;
&lt;li&gt;Evangelo Stavro Prodromou&lt;/li&gt;
&lt;li&gt;Evgeni Ku&lt;/li&gt;
&lt;li&gt;Glenn Thompson&lt;/li&gt;
&lt;li&gt;James Luke&lt;/li&gt;
&lt;li&gt;Jonathan Wright&lt;/li&gt;
&lt;li&gt;Michel Lind&lt;/li&gt;
&lt;li&gt;Mike Ledoux&lt;/li&gt;
&lt;li&gt;Nathan TeBlunthuis&lt;/li&gt;
&lt;li&gt;Nia Bickford&lt;/li&gt;
&lt;li&gt;Noah Beasley&lt;/li&gt;
&lt;li&gt;Steve Sprang&lt;/li&gt;
&lt;li&gt;Travis Smith&lt;/li&gt;
&lt;li&gt;Travis Vachon&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Bronze tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Alan Zimmerman&lt;/li&gt;
&lt;li&gt;Aria Stewart&lt;/li&gt;
&lt;li&gt;BJ Bolender&lt;/li&gt;
&lt;li&gt;Ben Hamill&lt;/li&gt;
&lt;li&gt;Benjamin Grimm-Lebsanft&lt;/li&gt;
&lt;li&gt;Brooke Vibber&lt;/li&gt;
&lt;li&gt;Brooklyn Zelenka&lt;/li&gt;
&lt;li&gt;Carl A&lt;/li&gt;
&lt;li&gt;Crazypedia No&lt;/li&gt;
&lt;li&gt;Ellie High&lt;/li&gt;
&lt;li&gt;François Joulaud&lt;/li&gt;
&lt;li&gt;Gerome Bochmann&lt;/li&gt;
&lt;li&gt;Grant Gould&lt;/li&gt;
&lt;li&gt;Gregory Buhtz&lt;/li&gt;
&lt;li&gt;Ivan Sagalaev&lt;/li&gt;
&lt;li&gt;James Smith&lt;/li&gt;
&lt;li&gt;Jason Wodicka&lt;/li&gt;
&lt;li&gt;Jeff Forcier&lt;/li&gt;
&lt;li&gt;Marty McGuire&lt;/li&gt;
&lt;li&gt;Mason DeVries&lt;/li&gt;
&lt;li&gt;Michael Orbinpost&lt;/li&gt;
&lt;li&gt;Neil Brudnak&lt;/li&gt;
&lt;li&gt;Nelson Pavlosky&lt;/li&gt;
&lt;li&gt;Philipp Nassua&lt;/li&gt;
&lt;li&gt;Robin Heggelund Hansen&lt;/li&gt;
&lt;li&gt;Ron Welch&lt;/li&gt;
&lt;li&gt;Stefan Magdalinski&lt;/li&gt;
&lt;li&gt;Stephen Herrick&lt;/li&gt;
&lt;li&gt;Steven De Herdt&lt;/li&gt;
&lt;li&gt;Tamara Schmitz&lt;/li&gt;
&lt;li&gt;Thomas Talbot&lt;/li&gt;
&lt;li&gt;William Murphy&lt;/li&gt;
&lt;li&gt;a b&lt;/li&gt;
&lt;li&gt;chee rabbits&lt;/li&gt;
&lt;li&gt;r g&lt;/li&gt;
&lt;li&gt;terra tauri&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Until next time, happy hooting! 🦉&lt;/p&gt;
</content><source><title>spritely.institute</title></source></entry><entry><title>Idiomdrottning: Pixel art apps on F-Droid, comparison</title><link href="https://idiomdrottning.org/pixel-art-android" rel="alternate"/><id>https://idiomdrottning.org/pixel-art-android</id><updated>2026-05-09T11:33:00+02:00</updated><author><name>Idiomdrottning</name></author><content type="html">&lt;div&gt;&lt;div&gt;&lt;p&gt;Here’s a comparison between the three pixel/​sprite/​tile making apps I could find on F-Droid. I know there’s stuff in that vein on Varvara, but I haven’t figured out a good way to run Varvara apps on Android yet, especially in a way where I could get files in and out. (Definitively still interested in that approach though.) So here’s PxerStudio, Pixel Artist, and PixaPencil.&lt;/p&gt;&lt;h2 id=&quot;pxerstudio&quot;&gt;PxerStudio&lt;/h2&gt;&lt;p&gt;First I tried &lt;strong&gt;PxerStudio&lt;/strong&gt;. My initial review of this was: Okay, I can use this one, but I really hope one of the other options is better. Why?&lt;/p&gt;&lt;p&gt;Because it’s “floaty” and “fidgety” in a way that makes my nerves knot up. This floatingness starts right away even when selecting the resolution (for all three of these apps I used 16×16) requires those aaaaawful number-sliders Android has. It feels horrible trying to get it to land on exactly sixteen.&lt;/p&gt;&lt;p&gt;Same goes for selecting colors: there’s no way to use palettes or entering hex digits or RGB values. There’s a color picker which you’ll have to rely on religiously. So if you reverse-engineer the project format you could open images with a palette base layer to pick from.&lt;/p&gt;&lt;p&gt;Also don’t press “back” by mistake because it might close the whole thing down (without saving, it seemed like,o but I’m not sure).&lt;/p&gt;&lt;p&gt;Placing the actal pixels is the biggest problem. There are three options: a drawing tool (basically a one pixel brush), a line tool, and a box tool. And a flood fill that does work well. The line tool doesn’t actually draw full lines if you go at an angle; it’s really conservative and only places the pixels it’s sure of. So it might only place two or three pixels inbetween long gaps that you’d have to fill in by hand. That’s fine. The biggest lack is a way to just tap in pixels. Tapping on a pixel doesn’t do anything, only dragging does. So I’m constantly adding pixels by mistake when I accidentally drag but where I do want to add pixels, I &lt;em&gt;have&lt;/em&gt; to drag. The box-drawing tool is almost the best tool since you can make 1×1 “boxes” to make pixels but that still requires dragging.&lt;/p&gt;&lt;p&gt;There’s full undo support though, and that mitigates a lot of these issues. But wow is this app an anxiety factory for me.&lt;/p&gt;&lt;p&gt;The export options are great (of the three apps this one exports the best) and unique among the three apps is that you can use layers. The layers is a killer feature that might push me into choosing this one over the others.&lt;/p&gt;&lt;h2 id=&quot;pixel-artist&quot;&gt;Pixel Artist&lt;/h2&gt;&lt;p&gt;Okay TL;DR: probably don’t use this &lt;strong&gt;Pixel Artist&lt;/strong&gt; until they implement better export options.&lt;/p&gt;&lt;p&gt;Here we go the opposite direction with an extremely minimalist app that only has one drawing tool: tap on a square (a pixel) to make it the selected color. Long press on a pixel to color-pick from it. No other tools, this is all you’ve got, and the only available size is 16×16 which might be a showstopper for some projects but suits me perfectly.&lt;/p&gt;&lt;p&gt;In addition to the awesome color-pick-by-long-press super power, there’s a predefined palette along one edge (and that’s your only “toolbar”, the palette); you can’t import palettes but you can replace colors by long-pressing them. However, those new colors you can only select by R, G, and B sliders (and no number so you can’t select a specific R, G or B value, just ballpark). If you save or reload a file, you still get the default palettes and your customly added colors are gone. You can still color pick them from the image but you can’t copy picked colors into the palette. So maybe don’t use custom colors except the default palette is bad with no ramps, all colors the same brightness, a single yellow and seven nearly indistinguishable greens.&lt;/p&gt;&lt;p&gt;There’s no zoom option either, so on the Retroid Pocket Classic, the image doesn’t fit without panning (although I can see the whole image by opening the file menu, where it’s embedded) and on the Paper 7 (which has fewer pixels than the &lt;abbr title=&quot;Retroid Pocket Classic&quot;&gt;RPC&lt;/abbr&gt; so apparently this is determined by display size, not pixel density), there is a huge white margin to the right and below the image.&lt;/p&gt;&lt;p&gt;I can’t comfortably draw with a “tap by tap” app like this&lt;small&gt; (and I hope you like tapping because a 16×16 image requires 256 taps)&lt;/small&gt;, but if I sketch on 1mm grid paper, I can then “digitalize” those paper sketches by usig this Pixel Artist app as a “data entry tool”. The garish, unramped colors would’ve been fine if if they had at least been distinguishable, since I can re-palette them in the game engine and I’d only be using the app to get a digital representation of a paper sketches and I can use all kinds of colored pens when making the paper sketch versions on grid paper.&lt;/p&gt;&lt;p&gt;Dragging with a single finger pans the image and tapping sets a pixel to the chosen color.
There’s no undo at all.&lt;/p&gt;&lt;p&gt;So far some pros and cons: great for quickly placing pixels with precision, but that’s &lt;em&gt;all&lt;/em&gt; it can do. Now for what breaks it: exporting the images! Three issues with that:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;You need to remember to turn off the grid before exporting, otherwise the grid will be visible in the image (and it’ll have a different resolution so it can fit the grid). Not a dealbreaker but I do want the grid on while drawing (that especially goes for this app with it’s dot-by-dot mental model) so having to turn that off before exporting each image is a chore.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;One pixel is not one pixel. It’s display dependent. So images I made on the RPC are 1280×1280 (that’s 80×80 pixels per pixel) while images I made on the Paper 7 are 640 by 640 (so 40 by 40 pixels per pixel). That’s nothing imagemagick can’t fix (it’s only a waste of space and bandwith but I can live with that).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Now to the biggest problem: that big exported picture is a JPEG for some reason! What in the heck! Yeah, yeah, ImageMagick’s convert utility can probably reindex and requantize the images to hopefully dodge any artifacts so the JPEG decision doesn’t have to ruin anything except it also wastes space.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;So okay, my lede on Pixel Studio said not to use until they fix exports not &lt;em&gt;literally&lt;/em&gt; true because ImageMagick &lt;em&gt;can&lt;/em&gt; rescue the image data. Just not easily.&lt;/p&gt;&lt;h2 id=&quot;pixapencil&quot;&gt;PixaPencil&lt;/h2&gt;&lt;p&gt;Uh-oh! F-Droid warns that “source code no longer available” for &lt;strong&gt;PixaPencil&lt;/strong&gt;, so I was really hoping it wasn’t gonna be the best of the three. (Turns out the sitaution is that the app has gone proprietary. It’s “source-available” but for our &lt;abbr title=&quot;Debian Free Software Guidelines&quot;&gt;DFSG&lt;/abbr&gt; purposes it might as well be in /dev/null. Except! Older versions can be forked! That’s a distinction I sometimes wish F-Droid would make but maybe that’s splitting hairs. I see that on F-Droid apps and I think oh no there’s been a drive failure and the source code is literally gone (I’ve been there, fam♥︎😭) but what happened instead is that the main dev is making no more DFSG-free updates so may the forks be with you. Lookin at the sourcecode there’s a subpackage named “dao” which is a pretty bad red flag for me.)&lt;/p&gt;&lt;p&gt;Unfortunately it might the best one.&lt;/p&gt;&lt;h3 id=&quot;how-good-is-it-at-the-basics&quot;&gt;How good is it at the basics?&lt;/h3&gt;&lt;p&gt;It doesn’t have layers, is the major missing feature that PxerStudio
had.
Export options are also limited compared to PxerStudio but it’s a good
clean PNG where you can select raw (one pixel is one pixel, great for
using in the game project) or scaled (one pixels is bigger, great for
display and posting).
That’s all I need.
Other tools can take it from there.
The PNG images are in indexed, 8-bit PaletteAlpha format which is
perfect for this.&lt;/p&gt;&lt;p&gt;Of the three apps, this is the only one that lets you actually enter any hex triplet color (or I guess hex quadruplet since there’s alpha too). You can even import entire palettes&lt;small&gt; (You need to use a specific website to do that, though. It’s called “Lospec”. You need to paste only the last part of the URL, the “palette identifier”.)&lt;/small&gt;.&lt;/p&gt;&lt;p&gt;The only way to zoom is the zoom buttons and the only way to pan is the panning tool. Okay, I love that restriction. This means that dragging my finger (or pen but my pen is broken right now) over the screen does only one thing: the selected tool. Tapping pixels to add them is even more reliable than in Pixel Artist (where it semeed like it sometimes did require a little effort), and as I said, Pxer Studio can’t even do that.&lt;/p&gt;&lt;p&gt;The line tool is crisp and reliable and there are a couple of other tools like boxes, flood fill, polylines and so on.&lt;/p&gt;&lt;h3 id=&quot;beyond-the-basics&quot;&gt;Beyond the basics&lt;/h3&gt;&lt;p&gt;I’ve got to remember than if anything in this section is bad, that’s fine, just don’t use it, it’s a “bonus section” anyway.&lt;small&gt; (For example, the project I’m working on doesn’t benefit from dithering.)&lt;/small&gt; There’s mirror symmetry, dither and spray tools, other brush shapes (and your currently selected brush is used when using the line tools). There’s darkening, lightening, and color-inverting the entire image (maybe would’ve been more useful if there had been layers and/or selections).&lt;/p&gt;&lt;p&gt;There’s also a “darken/lighten” tool which I love and hate. &lt;em&gt;Be careful&lt;/em&gt; when using it because if you accidentally lift your pen, it re-darkens already darkened squares or re-lightens already lightened ones, and it also lightens any black outlines you have. (Again, no layers…)&lt;/p&gt;&lt;p&gt;It does &lt;em&gt;not&lt;/em&gt; stick to the ramps in your palette, is the major problem. Those caveats aside, I’m still thinking I might want to use this tool a lot, to crank out a bunch of sprites quickly: I’ll just make a way simpler hue-only palette for the main flats and then shade them with this darken tool, being more restrictive against lighten since that can mess up the outlines. I can re-palette the sprites in the game engine anyway later. But, this darken/lighten tool is at the expense of a more generic “only replace selected color” draw setting that MS Paintbrush had back in the early 90s. It’s both worse and better because if you’re satisfied with what it does, it’s fewer clicks to add a li’l depth to your images and make them a li’l less NES and a li’l more TG-16.&lt;/p&gt;&lt;p&gt;I also like the “pixel perfect” setting. With it on, I can draw sloppily and it deletes stray pixels after I lift my finger. I love that it’s not the default because it’s pretty surprising behavior, but it’s a great option that I’ll use often if I do go with this app.&lt;/p&gt;&lt;h2 id=&quot;emacs-in-an-ssh&quot;&gt;Emacs in an SSH&lt;/h2&gt;&lt;p&gt;My original plan when I got this 1mm grid paper was to enter the
pixels directly into Emacs and writing a li’l something something to
convert it into pixel data (and then I learned that &lt;code&gt;pceas&lt;/code&gt; has a
hex-nybble-to-pixel-index importer built in which made this even
easier).&lt;/p&gt;&lt;p&gt;I mean something like:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;00A0
00A0
00A0
00A0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(that’s a li’l 4 by 4 toy example, the real entries would be 8 by 8 or 16 by 16.)&lt;/p&gt;&lt;p&gt;I quickly learned that as much as I actually do type stuff in here with the &lt;abbr title=&quot;on-screen keyboard&quot;&gt;OSK&lt;/abbr&gt;, that might be fine for coding but not so much for this amount of “data entry”.&lt;/p&gt;&lt;p&gt;In other words, I can’t do it on-the-go unless I bring my &lt;a title=&quot;Atreus Saga, part seven!&quot; href=&quot;/atreus-saga-part-seven&quot;&gt;keyboard&lt;/a&gt;. But at home or when I &lt;em&gt;do&lt;/em&gt; have my keyboard this might still be the best method for getting paper-sketched ideas into the game! I can choose homerow glyphs or otherwise comfortably-placed glyphs while entering and fix them with a &lt;code&gt;tr&lt;/code&gt; filter.&lt;/p&gt;&lt;p&gt;Kind of sucks that the grid paper has “major grid line” every ten lines instead of every eight lines but I can live with that (I’ve already made plenty of sprites with this method and it works fine).&lt;/p&gt;&lt;h2 id=&quot;nostalgia-for-my-desktop&quot;&gt;Nostalgia for my desktop&lt;/h2&gt;&lt;p&gt;When I still had my desktop computer I loved making pixel art in a combination of Inkscape, MyPaint and GIMP #ChangeTheName. Waaay back in the day I’ve used Synfig also. Inkscape might sound like a bad choice for pixelart and it was, until I found some extensions that made it better. The icons I made for Heartfeed where all made in Inkscape, manually rehinted for every size. (Well, some of them started life in Blender but I did the hinting in Inkscape). Knowing that outlined objects need to start at .5-offset pixel increments while un-outlined objects need to start at integer pixel increments, that sort of stuff is necessary to be aware of when working with Inkscape. It’s definitively not safe-and-good straight out of the box. It’s just that at the time my brain was just really attuned into Inkscape. GIMP #ChangeTheName is also great for color curves, scaling options, applying gradients and so on, and there’s a million formats to export and import, and it’s great for making animations easily.&lt;/p&gt;&lt;h2 id=&quot;csp-non-foss-alert&quot;&gt;CSP (non-FOSS alert)&lt;/h2&gt;&lt;p&gt;Then after I moved apartments and couldn’t use my desktop anymore because of lack of physical space and lack of power outlets and I’m relegated to tablets I got CSP for the iPad but I’ve let that subscription lapse. Looking into maybe getting a cross-device renewal later that works on both iPad and Android.&lt;/p&gt;&lt;p&gt;CSP was okay for pixel art actually. I wasn’t that happy with &lt;a title=&quot;Dil&quot; href=&quot;https://idiomdrottning.org/dil.png&quot;&gt;how the one image I made with it&lt;/a&gt; turned out, but I was pretty happy with the tools. The “pixel perfect” drawing mode that PixaPencil has would’ve been welcome, but in exchange it’s freeing to be able to use pencil sketching and painting tools for the first iterations and then go down to the nitty gritty for refining them. We get all symmetry lines, skewing, molding, pushing, warping, masking, layer joy we could ever need and can then cook it down to pixel size.&lt;/p&gt;&lt;p&gt;That’s an approach that none of these specialized pixel art apps can do.&lt;/p&gt;&lt;p&gt;It’s the difference between drawing and painting. Sometimes painting feels like molding clay, I love it, I can push and pull, add and sculpt. Sketching has some of the same quality with a loose-enough pencil scribbling approach (I like normal HB pencils the best). Drawing implies laying down the lines exactly where they should be and getting them right in the first try. That’s the mentality the pixel apps require and that’s a pretty huge limitation on all of them. They’re very waterfall and not so iterative.&lt;/p&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Nothing I can do on tablet, among the options I’ve found so far, comes close to what I could do on my Debian desktop with MyPaint, Krita, Blender, Inkscape, and GIMP #ChangeTheName. Except for CSP which did come pretty close.&lt;/p&gt;&lt;p&gt;Of the three Android options I’m gonna go with the old version of PixaPencil in the hope of forks. I’m not saying no to the Varvara stuff if I can get them to work on Android although I’m working on a project that uses four-bit color, not two-bit.&lt;/p&gt;&lt;p&gt;If I ever rejoin society I might go trawling on the App Store and Play
Store (including considering maybe renewing my CSP subscription).&lt;/p&gt;&lt;p&gt;Definitively not throwing out my 1mm grid paper either. After looking at these pixel apps I’m so glad I got it. I’m sure some of the sprites and tiles will be drawn entirely that way and hand-entered into Emacs, others will be drawn mostly that way, and hand-entered and refined in one of the pixel apps, some will made primarily in the pixel apps based on loose paper sketches, and some won’t use the grid paper at all and that’s fine too. I’m completely overwhelmed by the amount of art I have to make so I really appreciate the multi-faceted approach.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><source><title>Idiomdrottning</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 271: Random port libraries</title><link href="https://srfi.schemers.org/srfi-271/" rel="alternate"/><id>https://srfi.schemers.org/srfi-271/</id><updated>2026-05-03T12:00:00-08:00</updated><author><name>Wolfgang Corcoran-Mathe</name></author><content type="html">SRFI 271 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;This SRFI proposes a pattern of libraries for binary input ports
  that produce random bytes. Libraries are divided into
  “randomized” and “determinized” categories to address different
  uses of random data. The design leaves the details of random
  number generation to the implementer and the transformation of
  bytes to other types (floats, etc.) to higher-level libraries.
  A mechanism for saving random-port states as bytevectors and for
  propagating those states to new ports is also provided.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 270: Hexadecimal Floating-Point Constants</title><link href="https://srfi.schemers.org/srfi-270/" rel="alternate"/><id>https://srfi.schemers.org/srfi-270/</id><updated>2026-05-01T12:00:00-08:00</updated><author><name>Peter McGoron</name></author><content type="html">SRFI 270 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
 Floating-point numbers are usually stored in radix 2, but are written by
 users in radix 10. This SRFI introduces Scheme syntax for hexadecimal floating
 point constants based on C99's syntax, that use radix 16 for writing
 the integer and fractional part, and a radix 10 exponent part that raises
 the whole value to a power of 2.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>jointhefreeworld: Why I Still Reach for Scheme and Lisp Instead of Haskell</title><link href="https://jointhefreeworld.org/blog/articles/lisps/why-i-still-reach-for-scheme-instead-of-haskell/index.html" rel="alternate"/><id>https://jointhefreeworld.org/blog/articles/lisps/why-i-still-reach-for-scheme-instead-of-haskell/index.html</id><updated>2026-04-29T01:00:00+02:00</updated><content type="html">&lt;div id=&quot;content&quot; class=&quot;content max-w-full&quot;&gt; &lt;p&gt;
There is a persistent tension in software engineering between the beautiful, mathematically pure ideal of a program, and the messy, pragmatic reality of just getting things done. Over my career, I’ve explored the depths of both extremes in an attempt to find my personal sweet spot for hacking.
&lt;/p&gt;

 &lt;p&gt;
Before you sharpen your keyboards and start a flame war over the title, let me point out that I haven’t written this post to talk bad about  &lt;a href=&quot;https://www.haskell.org/&quot;&gt;Haskell&lt;/a&gt;, or any other tool for that matter. In fact, I love Haskell. I taught myself, banged my head against the wall over the course of three years, and built several real-world projects with it (some even became a bit lucrative).
&lt;/p&gt;

 &lt;p&gt;
Between my time in the web development world, the  &lt;a href=&quot;https://go.dev/&quot;&gt;Go&lt;/a&gt; world, the JVM world with  &lt;a href=&quot;https://www.java.com/&quot;&gt;Java&lt;/a&gt;,  &lt;a href=&quot;https://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt; and  &lt;a href=&quot;https://kotlinlang.org/&quot;&gt;Kotlin&lt;/a&gt;, and my long history hacking in  &lt;a href=&quot;https://lisp-lang.org/&quot;&gt;Lisp&lt;/a&gt; ( &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;,  &lt;a href=&quot;https://common-lisp.net/&quot;&gt;Common&lt;/a&gt;,  &lt;a href=&quot;https://schemers.org/&quot;&gt;Scheme&lt;/a&gt;), I have come to deeply appreciate functional programming.
&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt; &lt;h2&gt;Enlightening as it can be  &lt;a id=&quot;enlightening-as-it-can-be&quot; class=&quot;anchor&quot; href=&quot;#enlightening-as-it-can-be&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgef415a5&quot;&gt;
 &lt;p&gt;
Haskell has what likely is the most amazing, enlightening and complex type system to work with (as do more  &lt;a href=&quot;https://en.wikipedia.org/wiki/ML_(programming_language)&quot;&gt;ML languages&lt;/a&gt;).
&lt;/p&gt;

 &lt;p&gt;
It is also the undisputed king of introducing mathematical ideas and concepts to programming, and popularizing them. Haskell circles are frequented by PhDs, computer science researchers,  &lt;a href=&quot;https://en.wikipedia.org/wiki/Category_theory&quot;&gt;category theorists&lt;/a&gt; and all kinds of smart people (don’t underestimate other communities, like Schemers though).
&lt;/p&gt;

 &lt;p&gt;
Some of the amazing innovations of Haskell or that it has helped popularize, which blew my mind several times:
&lt;/p&gt;
 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Algebraic_data_type&quot;&gt;algebraic data types&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Pattern_matching&quot;&gt;pattern matching&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Functor&quot;&gt;functors&lt;/a&gt;,  &lt;a href=&quot;https://en.wikipedia.org/wiki/Monad_(functional_programming)&quot;&gt;monads&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Monoid&quot;&gt;monoids&lt;/a&gt;,  &lt;a href=&quot;https://en.wikipedia.org/wiki/Semigroup&quot;&gt;semigroups&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;effectful computation modelled as monads&lt;/li&gt;
 &lt;li&gt;purely functional domain-specific languages (DSLs)&lt;/li&gt;
 &lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
All these kind of things often feel bolted-on or missing entirely in other languages!
&lt;/p&gt;

 &lt;p&gt;
For all its brilliance, Haskell resists most of the attempts people make to just  &lt;b&gt;hack&lt;/b&gt; and write useful code  &lt;i&gt;quickly&lt;/i&gt;.
&lt;/p&gt;

 &lt;p&gt;
Specially people new to functional programming (or god forbid new to monads and functors! A monad is just a monoid in the category of endofunctors, what’s the problem?)
&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;&lt;/div&gt;
 &lt;h2&gt;When pragmatism enables actual productivity  &lt;a id=&quot;when-pragmatism-enables-actual-productivity&quot; class=&quot;anchor&quot; href=&quot;#when-pragmatism-enables-actual-productivity&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgaf369bf&quot;&gt;
 &lt;p&gt;
Scheme (and Lisp in general) might lack Haskell’s innovations and purity, favoring a minimalistic flexibility instead, but it mixes practicality with functional beauty in a way that makes it a functional language for human beings.
&lt;/p&gt;

 &lt;p&gt;
Actually, in my opinion, Scheme (and Lisp) allows you to express complex systems and problem domains in more simple terms than any other language can.
&lt;/p&gt;

 &lt;p&gt;
Take a recent adventure of mine, for example. I was spinning up a prototype for a bookmark management tool, just one of many projects I’ve come up with over the years.
&lt;/p&gt;

 &lt;p&gt;
I started in Haskell as I thought the beauty of data modelling and pure side-effect-free reasoning would work well: it’s also fast, elegant, and once you’ve used modules like  &lt;a href=&quot;https://hackage.haskell.org/package/parsec&quot;&gt;Parsec&lt;/a&gt;,  &lt;a href=&quot;https://docs.servant.dev/&quot;&gt;Servant&lt;/a&gt;, and  &lt;a href=&quot;https://hackage.haskell.org/package/optparse-applicative&quot;&gt;optparse-applicative&lt;/a&gt;, it’s tough to imagine writing certain things, like a parser, without it.
&lt;/p&gt;

 &lt;p&gt;
One of the steps in the proof-of-concept was transforming some data models to XML and output them to a file.
&lt;/p&gt;

 &lt;p&gt;
If I were doing this in Kotlin or Java, it would be trivial: drop a dependency into Gradle, wire up  &lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt; or a standard DOM parser, and ten minutes later the data is in memory and ready to manipulate.
&lt;/p&gt;

 &lt;p&gt;
After a frustrating hour with my Haskell project, and even after years of experience with the language, I was still wrestling with the dependencies, and later with monadic API, and I ended up giving up on the whole thing after I noticed I even forgot what I was doing in the first place.
&lt;/p&gt;

 &lt;p&gt;
This has often been my friction point with Haskell. It is beautiful, but it fights you when you just want to get your hands dirty and prototype, without a  &lt;i&gt;big design upfront&lt;/i&gt; even though  &lt;a href=&quot;https://en.wikipedia.org/wiki/Type-driven_development&quot;&gt;type-driven development&lt;/a&gt; can also be nice and work well in some cases.
&lt;/p&gt;

 &lt;p&gt;
Scheme ( &lt;a href=&quot;https://www.gnu.org/software/guile/&quot;&gt;GNU Guile&lt;/a&gt; for me) doesn’t have Haskell’s brutally efficient compiler, although it is quite speedy thanks to the C foundation. What it has is the terseness, power, and more importantly,  &lt;b&gt;it makes the actual act of hacking a joy&lt;/b&gt;.
&lt;/p&gt;

 &lt;p&gt;
As elegant as Haskell’s purely functional foundation is, it can really complicate simple, crucial, impure tasks like writing to files or talking over a network.
&lt;/p&gt;

 &lt;p&gt;
Monads are Haskell’s answer to this, but they often feel like a heavy abstraction tax; they allow you to write useful software, but they rarely make it intuitive or fast to prototype.
&lt;/p&gt;

 &lt;p&gt;
These kind of heavy-handed abstractions are in my opinion really beautiful, but not justifiable for most projects. Please do ask yourself, do I really need a functional effect system, is it worth the complexity and cognitive load? Do I really need the pure/impure computation strictness enforced at compile time? Remember that later, just adding a simple  &lt;code&gt;print&lt;/code&gt; somewhere is not going to work without refactor (welcome to the  &lt;code&gt;IO&lt;/code&gt; monad).
&lt;/p&gt;

 &lt;p&gt;
As a long-time Lisper, for me this is a massive barrier to usability. In many ways, you can only fix what you can observe.
&lt;/p&gt;

 &lt;p&gt;
Scheme happily sacrifices academic purity so you can slap a  &lt;code&gt;(write ...)&lt;/code&gt; anywhere in your code and instantly see what’s going on. I’m sure a Haskell purist is burying their face in their hands right now, citing  &lt;code&gt;Debug.Trace&lt;/code&gt; or questioning why I’d want side-effects in a lazy, well-optimized language. They aren’t technically wrong, but the friction added to quick-and-dirty debugging is a tax I am simply not willing to pay when I’m trying to move fast.
&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;&lt;/div&gt;
 &lt;h2&gt;Meta-programming and DSLs  &lt;a id=&quot;meta-programming-and-dsls&quot; class=&quot;anchor&quot; href=&quot;#meta-programming-and-dsls&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org7488455&quot;&gt;
 &lt;p&gt;
The second problem with Monads is directly tied to their greatest strength: they are synonymous with  &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;Domain Specific Languages&lt;/a&gt; (DSLs).
&lt;/p&gt;

 &lt;p&gt;
The promise of DSLs is fantastic—don’t write a complex program to solve a problem; write a simple program in a bespoke language designed solely for that task. Parsec is the golden child here; the parsing function is practically identical to the  &lt;a href=&quot;https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form&quot;&gt;BNF grammar&lt;/a&gt;.
&lt;/p&gt;

 &lt;p&gt;
But the success of Parsec has filled  &lt;a href=&quot;https://hackage.haskell.org/&quot;&gt;Hackage&lt;/a&gt; with hundreds of bespoke DSLs for everything. One for parsing, one for XML, one for generating PDFs. Each is completely different, and each demands its own learning curve. Consider parsing XML, mutating it based on some JSON from a web API, and writing it to a PDF. In the Java ecosystem for example you expect a certain level of consistency. You pull in three libraries, and they generally follow familiar object-oriented or functional-lite conventions. But in Haskell, three DSLs designed for three different tasks usually mean the authors optimized strictly for the domain, completely ignoring syntax consistency. Instead of five minutes skimming JavaDocs, you have hours of DSL documentation and tutorials ahead of you.
&lt;/p&gt;

 &lt;p&gt;
As we Schemers know, Scheme is intentionally simple. That simplicity isn’t a limitation; it’s what makes it endlessly flexible.
&lt;/p&gt;

 &lt;p&gt;
While modern JVM languages rely heavily on reflection or complex compiler plugins (like Kotlin’s  &lt;a href=&quot;https://kotlinlang.org/docs/ksp-overview.html&quot;&gt;KSP&lt;/a&gt;) to achieve this, Lisp hackers have been effortlessly reshaping the language for decades using the powerful  &lt;a href=&quot;https://en.wikipedia.org/wiki/Macro_(computer_science)#Lisp_macros&quot;&gt;macro system&lt;/a&gt; and extending and bending the language to their will.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define-syntax&lt;/span&gt;  &lt;span class=&quot;org-variable-name&quot;&gt;define-repo-method&lt;/span&gt;
  ( &lt;span class=&quot;org-keyword&quot;&gt;syntax-rules&lt;/span&gt; ()
                ((_ method-name accessor docstring)
                 ( &lt;span class=&quot;org-keyword&quot;&gt;define*&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;method-name&lt;/span&gt; repo . args)
                   docstring
                   (apply (accessor repo) args)))))&lt;/pre&gt;

 &lt;p&gt;
Haskell, much like Scala’s advanced type-level programming, often requires a mountain of language extensions to achieve similar flexibility ( &lt;a href=&quot;https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/template_haskell.html&quot;&gt;Template Haskell&lt;/a&gt; and its powerful but scary API).
&lt;/p&gt;

 &lt;pre&gt;{-# LANGUAGE TemplateHaskell #-}
import Control.Monad
import Language.Haskell.TH

curryN :: Int -&gt; Q Exp
curryN n = do
  f  &lt;- newName &quot;f&quot;
  xs &lt;- replicateM n (newName &quot;x&quot;)
  let args = map VarP (f:xs)
      ntup = TupE (map (Just . VarE) xs)
  return $ LamE args (AppE (VarE f) ntup)&lt;/pre&gt;

 &lt;p&gt;
I’ve used Scheme for countless projects because of its combination of features and philosophies that bring it to my personal  &lt;i&gt;“sweet spot”&lt;/i&gt;. It’s also an advanced language, which keeps pioneering, and of unconstrained innovation (e.g.  &lt;a href=&quot;https://en.wikipedia.org/wiki/Delimited_continuation&quot;&gt;delimited continuations&lt;/a&gt;). When you want to mold the syntax directly to your will, Scheme gets out of your way and helps you achieve it.
&lt;/p&gt;

 &lt;p&gt;
Of course, to be completely fair about my toolkit, standard Scheme can sometimes lack the heavyweight, “batteries-included” ecosystem required for massive enterprise production compared to the JVM. Also, when compared to Haskell, Lisp compilers are modest and simple, at best, but that makes them also that much more approachable (and the error messages that much friendlier).
&lt;/p&gt;

 &lt;p&gt;
I’m not saying Scheme is objectively better than Haskell. Languages are tools, and we should choose the right tool for the job.
&lt;/p&gt;

 &lt;p&gt;
I will always remember all I learnt from Haskell’s functional beauty and ideas, but to me, Haskell remains a platonic ideal of a programming language: lighting the way in a certain direction, but a bit too rigid for most of what I do.
&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;&lt;/div&gt;
 &lt;h2&gt;Then there is the REPL: Interactive workflow, developer power  &lt;a id=&quot;then-there-is-the-repl-interactive-workflow-developer-power&quot; class=&quot;anchor&quot; href=&quot;#then-there-is-the-repl-interactive-workflow-developer-power&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org8e260f8&quot;&gt;
 &lt;p&gt;
A REPL (Read-Eval-Print Loop) is an interactive environment, which can be used connected to your console, running application, language compiler and more, which gives you superpowers as an engineer 🦸🏼.
&lt;/p&gt;

 &lt;p&gt;
Lisp dialects, more specifically Guile Scheme, have great support for this. I personally of course like to do this with  &lt;a href=&quot;https://guix.gnu.org/&quot;&gt;Guix&lt;/a&gt;,  &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;, ( &lt;a href=&quot;https://git.sr.ht/~abcdw/emacs-arei&quot;&gt;Arei/Ares&lt;/a&gt; +  &lt;a href=&quot;https://github.com/vspinu/sesman&quot;&gt;sesman&lt;/a&gt;) you can get an ultimate extensible powerful editor experience, miles ahead of traditional IDEs 🐂 .
&lt;/p&gt;

 &lt;p&gt;
And no, it’s not the same kind of REPL you know from Haskell (GHCIDE or others) or Python. Lisp REPLs can do so much more and integrate seamlessly to your editor. Evaluate, check, change and debug live, seamlessly.
&lt;/p&gt;

 &lt;p&gt;
It fundamentally changes the development workflow by eliminating the slow  &lt;i&gt;edit, save, compile, run&lt;/i&gt; cycle. Instead of writing a whole program and then running it to see what happens, you get a fast, conversational workflow. What does this mean for in practice?
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Incremental Development:&lt;/b&gt; Write, test, inspect, evaluate one function or even one line at a time. Get immediate feedback without running the entire app.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Powerful Debugging:&lt;/b&gt; Forget adding  &lt;code&gt;print&lt;/code&gt; statements and restarting. You can pause, inspect objects, change values, and even redefine a broken function on the fly to test a fix in any environment (yes even in production, while running).&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Fast Prototyping &amp; Learning:&lt;/b&gt; Instantly experiment with a new library or API. Just load it and start calling functions to see how they work, which is much faster than only reading documentation.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
When integrated into your code editor, you can execute any piece of code (a line, a selection, or a file) with a keyboard shortcut and see the result instantly, creating a seamless and powerful development experience.
&lt;/p&gt;

 &lt;p&gt;
Overall Lisp languages are simply the sweet spot for me and of what I consider good developer experience. They also give you super powers and let you create beatiful systems that can last.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content><source><title>jointhefreeworld</title></source></entry><entry><title>Arthur A. Gleckler: validate-email-address</title><link href="https://speechcode.com/blog/validate-email-address" rel="alternate"/><id>https://speechcode.com/blog/validate-email-address</id><updated>2026-04-27T12:00:00Z</updated><author><name>Arthur A. Gleckler</name></author><content type="html">
&lt;article class=&quot;post validate-email-address&quot;&gt;&lt;img class=&quot;hero&quot; src=&quot;https://speechcode.com/blog/validate-email-address/validate-email-address.svg&quot;&gt;
  &lt;div class=&quot;metadata&quot;&gt;
    &lt;div class=&quot;date&quot;&gt;Mon 27 Apr 2026&lt;/div&gt;
    &lt;div class=&quot;labels&quot;&gt;&lt;a href=&quot;https://speechcode.com/blog/label/scheme&quot;&gt;scheme&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
  &lt;div class=&quot;contents&quot;&gt; 
    &lt;p&gt;I'm building a new web site in Scheme for BALISP, the Bay Area Lisp
       and Scheme Users Group. (The site isn't launched yet, but will replace
       the current Meetup.com redirect at &lt;a href=&quot;https://balisp.org/&quot;&gt;balisp.org&lt;/a&gt; sometime before our next meeting.)&lt;/p&gt; 
    &lt;p&gt;The BALISP site needs to validate users' email addresses to make sure
       that they comply with &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc5322.html&quot;&gt;RFC 5322&lt;/a&gt;, but I couldn't find a complete validator written in Scheme.
       Everything I read said that making a correct validator is a surprising
       amount of work. Many people write a complicated regular expression
       that produces false positives and negatives, but that felt wrong.&lt;/p&gt; 
    &lt;p&gt;&lt;span&gt;Fortunately, Dominic Sayers had published a thorough set of tests as
         part of his &lt;/span&gt;&lt;a href=&quot;https://github.com/dominicsayers/isemail&quot;&gt;isemail&lt;/a&gt;&lt;span&gt; validator, written in PHP. With those tests and the help of Claude
         Code, I was able to implement a complete validator that works in Chibi
         Scheme and Gauche Scheme. My new Scheme library is called &lt;a href=&quot;https://github.com/arthurgleckler/validate-email-address&quot;&gt;validate-email-address&lt;/a&gt;, and is licensed under the MIT license except for the test data,
         which are licensed under Dominic's original BSD 3-Clause license. I
         hope it's useful to other Scheme hackers.&lt;/span&gt;&lt;br&gt;&lt;/p&gt;&lt;/div&gt;&lt;/article&gt;</content><source><title>Arthur A. Gleckler</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 267: Raw String Syntax</title><link href="https://srfi.schemers.org/srfi-267/" rel="alternate"/><id>https://srfi.schemers.org/srfi-267/</id><updated>2026-04-26T12:00:00-08:00</updated><author><name>Peter McGoron</name></author><content type="html">SRFI 267 is now in &lt;em&gt;final&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
    Raw strings are a lexical syntax for strings that do
    not interpret escapes inside of them and are useful in
    cases where the string data has a lot of characters such as
    &lt;code&gt;\&lt;/code&gt; or &lt;code&gt;&quot;&lt;/code&gt; that would otherwise
    have to be escaped. This SRFI proposes a raw string syntax that
    allows for a customized delimiter to enclose the character
    data. Importantly, for any string, there exists a delimiter
    such that the raw string using that delimiter can represent
    the string verbatim. The raw strings in this SRFI do not do
    any special whitespace handling.
&lt;/p&gt;
&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>spritely.institute: Spritely Goblins v0.18.0: Sleepy actors!</title><link href="https://spritely.institute/news/spritely-goblins-v0-18-0-sleepy-actors.html" rel="alternate"/><id>https://spritely.institute/news/spritely-goblins-v0-18-0-sleepy-actors.html</id><updated>2026-04-21T12:00:00Z</updated><author><name>Dave Thompson and Christine Lemmer-Webber</name></author><content type="html">&lt;p&gt;&lt;img src=&quot;https://files.spritely.institute/images/blog/2026-04-21-sleepy-actors.png&quot; alt=&quot;Goblins version 0.18.0 release art: a Spritely goblin takes a nap in a chair by a fireplace, tea steams on a nearby table&quot;&gt;&lt;/img&gt;&lt;/p&gt;
&lt;p&gt;We’re excited to announce the release of &lt;a href=&quot;/goblins/&quot;&gt;Spritely Goblins&lt;/a&gt;
0.18.0!  This release features a new caching layer called “sleepy
actors”, OCapN protocol updates, and numerous bug fixes.  So get cozy
by the fire, pull out a steaming cup of tea, and let’s have a nice
relaxing read about this exciting new Goblins release!&lt;/p&gt;
&lt;h2&gt;Sleepy actors&lt;/h2&gt;
&lt;p&gt;Remember when we &lt;a href=&quot;https://spritely.institute/news/spritely-goblins-v0130-object-persistence-and-easier-io.html&quot;&gt;introduced persistence back in Goblins
0.13.0&lt;/a&gt;?
You’re not sure?  Okay, as a quick refresher, Goblins’ &lt;a href=&quot;https://spritely.institute/files/docs/guile-goblins/latest/Persistence.html&quot;&gt;persistence
system&lt;/a&gt;
is able to serialize a running Goblins program for you and wake it
back up later!  Pretty cool!&lt;/p&gt;
&lt;p&gt;Goblins is pretty smart about only saving the changes that need to
change. But... if we can save actors to disk, do we really need them
to be “awake” all at once?  What if we let them take a little nap, and
just woke them up when it’s time for them to do something?  Then they
could go back to bed when they aren’t needed anymore!&lt;/p&gt;
&lt;p&gt;Well that’s exactly what we’ve built!  Sleepy actors are a new,
optional caching layer has been added to the core of Goblins.  Actors
may now go to sleep or be woken up depending on a customizable caching
algorithm known as a “sleep strategy”.  When an actor goes to sleep,
it is saved to the vat’s persistence store but its reference remains
live.  When an asleep actor receives a message, its state is restored
from the vat’s persistence store and the message is processed as
usual.&lt;/p&gt;
&lt;p&gt;Goblins currently ships with two sleep strategies: an extremely simple
strategy where your little goblins head to bed after each and every
turn, and a “least recently used” algorithm, which functions as a hot
cache where only the most recently activated goblins stay awake, and
the rest go take a nap.&lt;/p&gt;
&lt;p&gt;For a feature that’s so sleepy, we’re pretty wired about its
potential, and we hope you are too!&lt;/p&gt;
&lt;h2&gt;OCapN protocol updates&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://ocapn.org&quot;&gt;OCapN&lt;/a&gt; draft specification has changed in the
time since the last Goblins release.  The &lt;code&gt;op:deliver-only&lt;/code&gt; operation
has been dropped in favor of a single &lt;code&gt;op:deliver&lt;/code&gt; operation.  GC
operations now accept a list of export positions instead of a single
position so that GC can be done in batches; their operation names have
likewise been changed to the plural form (&lt;code&gt;op:gc-export&lt;/code&gt; is now
&lt;code&gt;op:gc-exports&lt;/code&gt;, etc.)  The protocol version number has thus been
bumped, which means that applications built with an earlier release of
Goblins are incompatible with the OCapN shipped in this release.&lt;/p&gt;
&lt;h2&gt;Notable bug fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fixed a race condition when restoring multiple vats from persisted
data.  If Alice in vat A is referenced by Bob in vat B but &lt;em&gt;no other
actors in vat A&lt;/em&gt; then it was possible for Alice to be garbage
collected before vat B is restored.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fixed a signing oracle vulnerability in the WebSocket netlayer’s
designator authentication code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Getting the release&lt;/h2&gt;
&lt;p&gt;This release includes all the features detailed above as well as many
bug fixes.  See the
&lt;a href=&quot;https://codeberg.org/spritely/goblins/src/tag/v0.18.0/NEWS&quot;&gt;NEWS&lt;/a&gt; for
more information about all of the changes.&lt;/p&gt;
&lt;p&gt;As usual, Guix users can upgrade to 0.18.0 by running the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;guix pull
guix install guile-goblins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, you can find the tarball on our &lt;a href=&quot;https://spritely.institute/goblins/&quot;&gt;release
page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re making something with Goblins or want to contribute to
Goblins itself, be sure to join our community at
&lt;a href=&quot;https://community.spritely.institute/&quot;&gt;community.spritely.institute&lt;/a&gt;!
We also host regular office hours where you can come and ask questions
or discuss our projects.  Information about office hours is available
on the forum.  Thanks for following along and hope to see you there!&lt;/p&gt;
&lt;h2&gt;Thanks to our supporters&lt;/h2&gt;
&lt;p&gt;Your support makes our work possible!  If you like what we do, please
consider &lt;a href=&quot;/donate&quot;&gt;becoming a Spritely supporter today&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;Diamond tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Aeva Palecek&lt;/li&gt;
&lt;li&gt;Holmes Wilson&lt;/li&gt;
&lt;li&gt;Lassi Kiuru&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Gold tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Juan Lizarraga Cubillos&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Silver tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Austin Robinson&lt;/li&gt;
&lt;li&gt;Brit Butler&lt;/li&gt;
&lt;li&gt;Charlie McMackin&lt;/li&gt;
&lt;li&gt;Dan Connolly&lt;/li&gt;
&lt;li&gt;Deb Nicholson&lt;/li&gt;
&lt;li&gt;Evangelo Stavro Prodromou&lt;/li&gt;
&lt;li&gt;Glenn Thompson&lt;/li&gt;
&lt;li&gt;James Luke&lt;/li&gt;
&lt;li&gt;Jonathan Wright&lt;/li&gt;
&lt;li&gt;Michel Lind&lt;/li&gt;
&lt;li&gt;Mike Ledoux&lt;/li&gt;
&lt;li&gt;Nia Bickford&lt;/li&gt;
&lt;li&gt;Steve Sprang&lt;/li&gt;
&lt;li&gt;Travis Smith&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Bronze tier&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Alan Zimmerman&lt;/li&gt;
&lt;li&gt;BJ Bolender&lt;/li&gt;
&lt;li&gt;Ben Hamill&lt;/li&gt;
&lt;li&gt;Benjamin Grimm-Lebsanft&lt;/li&gt;
&lt;li&gt;Brooke Vibber&lt;/li&gt;
&lt;li&gt;Brooklyn Zelenka&lt;/li&gt;
&lt;li&gt;Crazypedia No&lt;/li&gt;
&lt;li&gt;Ellie High&lt;/li&gt;
&lt;li&gt;François Joulaud&lt;/li&gt;
&lt;li&gt;Gerome Bochmann&lt;/li&gt;
&lt;li&gt;Grant Gould&lt;/li&gt;
&lt;li&gt;Gregory Buhtz&lt;/li&gt;
&lt;li&gt;Ivan Sagalaev&lt;/li&gt;
&lt;li&gt;Jason Wodicka&lt;/li&gt;
&lt;li&gt;Jeff Forcier&lt;/li&gt;
&lt;li&gt;Marty McGuire&lt;/li&gt;
&lt;li&gt;Mason DeVries&lt;/li&gt;
&lt;li&gt;Michael Orbinpost&lt;/li&gt;
&lt;li&gt;Neil Brudnak&lt;/li&gt;
&lt;li&gt;Nelson Pavlosky&lt;/li&gt;
&lt;li&gt;Philipp Nassua&lt;/li&gt;
&lt;li&gt;Robin Heggelund Hansen&lt;/li&gt;
&lt;li&gt;Ron Welch&lt;/li&gt;
&lt;li&gt;Stephen Herrick&lt;/li&gt;
&lt;li&gt;Steven De Herdt&lt;/li&gt;
&lt;li&gt;Tamara Schmitz&lt;/li&gt;
&lt;li&gt;Thomas Talbot&lt;/li&gt;
&lt;li&gt;William Murphy&lt;/li&gt;
&lt;li&gt;a b&lt;/li&gt;
&lt;li&gt;r g&lt;/li&gt;
&lt;li&gt;terra tauri&lt;/li&gt;
&lt;/ul&gt;
</content><source><title>spritely.institute</title></source></entry><entry><title>Idiomdrottning: What Delta Chat was</title><link href="https://idiomdrottning.org/what-delta-chat-was" rel="alternate"/><id>https://idiomdrottning.org/what-delta-chat-was</id><updated>2026-04-11T08:52:17+02:00</updated><author><name>Idiomdrottning</name></author><content type="html">&lt;div&gt;&lt;div&gt;&lt;p&gt;Being able to quickly write replies to email, real actual email, was very valuable. That was the core of what drew me to Delta Chat.&lt;/p&gt;&lt;p&gt;There are plenty of proprietary email apps set up around that feature but in the free world, not so much. Delta Chat was it and it was a gem because it was in many ways better than those other sparks and spikes and whatever they were called.&lt;small&gt; Not to mention the incredible leap of faith it takes to go for a proprietary mail app since they can read the emails.&lt;/small&gt;&lt;/p&gt;&lt;p&gt;Delta Chat is rapidly moving away from being usable for that. If someone forks it or finds a good alternative (that’s FOSS, obvs), &lt;a href=&quot;mailto:sandra.snan@idiomdrottning.org&quot;&gt;I would love to know&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I know I’ve worked a little on Notmuch, and I’ve talked a little bit with the people who make aerc, but for all their conveniences they’re still traditional mail apps where the threads look like files that you have to open up and enter into and work with. The few extra clicks involved with using a normal mail app might sound like no big deal but it really adds up. All the opening, searching, archiving, threads management… Whereas with Delta Chat in its prime, you just see the message right away and can reply right away. Easy peasy.&lt;/p&gt;&lt;p&gt;Maybe K-9 but it got bought out by Mozilla and they hate autocrypt which I don’t. I think WKD is better, sure, but I try to use both. K-9 used to be one of the best autocrypt clients out there.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><source><title>Idiomdrottning</title></source></entry><entry><title>jointhefreeworld: Functional repository pattern in Scheme? Decoupling and abstracting the data layer in Lisp</title><link href="https://jointhefreeworld.org/blog/articles/lisps/functional-repository-pattern-in-scheme-with-macros/index.html" rel="alternate"/><id>https://jointhefreeworld.org/blog/articles/lisps/functional-repository-pattern-in-scheme-with-macros/index.html</id><updated>2026-04-11T01:00:00+02:00</updated><content type="html">&lt;div id=&quot;content&quot; class=&quot;content max-w-full&quot;&gt; &lt;p&gt;
 &lt;i&gt;Implementing the Repository Pattern with Hygienic Macros in Scheme&lt;/i&gt;
&lt;/p&gt;

 &lt;p&gt;
 &lt;b&gt;Hi everyone!&lt;/b&gt;
&lt;/p&gt;

 &lt;p&gt;
I’ve been working on a new approach for the data layer of my projects
lately, and I’d love to poke your brains and get some feedback.
&lt;/p&gt;

 &lt;p&gt;
Coming from a background in Scala, Java and other OOP languages and a
fascination for FP languages and Lisps (as well as Rust and Haskell),
I’ve seen a lot of patterns come and go.
&lt;/p&gt;

 &lt;p&gt;
Recently, I noticed a common anti-pattern in my own Scheme projects: a
tight coupling between my controller layer and the SQLite
implementation. It wasn’t ideal, and I really missed the clean
separation of the  &lt;b&gt;Repository Pattern&lt;/b&gt;.
&lt;/p&gt;

 &lt;p&gt;
So, I set out to decouple my data layer from my controller layer in the
MVC architecture I love. I wanted to do this using pure functional
programming, and I ended up building something really fun using
 &lt;b&gt;Scheme’s hygienic macros&lt;/b&gt;.
&lt;/p&gt;

 &lt;p&gt;
(If you want to see this implemented in a real project, check out my
example repo here:
 &lt;a href=&quot;https://codeberg.org/jjba23/lucidplan&quot;&gt;lucidplan&lt;/a&gt;)
&lt;/p&gt;

 &lt;p&gt;
I am working on adding it to
 &lt;a href=&quot;https://codeberg.org/jjba23/byggsteg&quot;&gt;byggsteg&lt;/a&gt; too.
&lt;/p&gt;

 &lt;p&gt;
I plan to bring this pattern to all my projects to reap the benefits of
the eDSL, better decoupling, and easier testing. Here is how I built it.
&lt;/p&gt;
 &lt;h2&gt;The Macros  &lt;a id=&quot;the-macros&quot; class=&quot;anchor&quot; href=&quot;#the-macros&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf5338b2&quot;&gt;
 &lt;p&gt;
I created two main macros.   &lt;code&gt;define-record-with-kw&lt;/code&gt; magically defines a
keyword-argument constructor, bypassing the need for strict parameter
ordering. It’s highly ergonomic.
&lt;/p&gt;

 &lt;p&gt;
 &lt;code&gt;define-repo-method&lt;/code&gt; is the real
superpower. It accepts any arity, plus optional or  &lt;code&gt;#:keyword&lt;/code&gt;
arguments. This saves a ton of work, reduces tedious parameter passing,
and gives you a very clean eDSL definition.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define-module&lt;/span&gt; ( &lt;span class=&quot;org-type&quot;&gt;lucidplan&lt;/span&gt; domain repo)
   &lt;span class=&quot;org-builtin&quot;&gt;#:declarative?&lt;/span&gt; #t
   &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (srfi srfi-9)
   &lt;span class=&quot;org-builtin&quot;&gt;#:export&lt;/span&gt; (define-repo-method define-record-with-kw))

( &lt;span class=&quot;org-keyword&quot;&gt;define-syntax&lt;/span&gt;  &lt;span class=&quot;org-variable-name&quot;&gt;define-repo-method&lt;/span&gt;
  ( &lt;span class=&quot;org-keyword&quot;&gt;syntax-rules&lt;/span&gt; ()
                ((_ method-name accessor docstring)
                 ( &lt;span class=&quot;org-keyword&quot;&gt;define*&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;method-name&lt;/span&gt; repo . args)
                   docstring
                   (apply (accessor repo) args)))))

( &lt;span class=&quot;org-keyword&quot;&gt;define-syntax&lt;/span&gt;  &lt;span class=&quot;org-variable-name&quot;&gt;define-record-with-kw&lt;/span&gt;
  ( &lt;span class=&quot;org-keyword&quot;&gt;syntax-rules&lt;/span&gt; ()
                ((_ (type-name constructor-name pred) kw-constructor-name
                    (field-name accessor-name) ...)
                 ( &lt;span class=&quot;org-keyword&quot;&gt;begin&lt;/span&gt;
                    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Define the standard SRFI-9 record&lt;/span&gt;
                   ( &lt;span class=&quot;org-keyword&quot;&gt;define-record-type&lt;/span&gt; type-name
                     (constructor-name field-name ...) pred
                     (field-name accessor-name) ...)

                    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Define the keyword-argument constructor&lt;/span&gt;
                   ( &lt;span class=&quot;org-keyword&quot;&gt;define*&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;kw-constructor-name&lt;/span&gt;  &lt;span class=&quot;org-builtin&quot;&gt;#:key&lt;/span&gt; field-name ...)
                     (constructor-name field-name ...))

                    &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Auto-export members&lt;/span&gt;
                   ( &lt;span class=&quot;org-keyword&quot;&gt;export&lt;/span&gt; type-name pred kw-constructor-name accessor-name
                           ...)))))&lt;/pre&gt;
&lt;/div&gt;
 &lt;h2&gt;Defining the Domain eDSL  &lt;a id=&quot;defining-the-domain-edsl&quot; class=&quot;anchor&quot; href=&quot;#defining-the-domain-edsl&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org20804ef&quot;&gt;
 &lt;p&gt;
Here is how I use those macros to define my DSL for a “projects” entity:
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define-module&lt;/span&gt; ( &lt;span class=&quot;org-type&quot;&gt;lucidplan&lt;/span&gt; domain project)
   &lt;span class=&quot;org-builtin&quot;&gt;#:declarative?&lt;/span&gt; #t
   &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (srfi srfi-9)
   &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (lucidplan domain repo)
   &lt;span class=&quot;org-builtin&quot;&gt;#:export&lt;/span&gt; (get-projects))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;-- Record definition ---&lt;/span&gt;

(define-record-with-kw ( &lt;span class=&quot;org-type&quot;&gt;&lt;project-repository&gt;&lt;/span&gt; %make-project-repository
                                             project-repository?)
                       mk-project-repository
                       (get-projects-proc repo-get-projects))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;--- eDSL: Embedded Domain Specific Language ---&lt;/span&gt;

(define-repo-method get-projects repo-get-projects
  &lt;span class=&quot;org-string&quot;&gt;&quot;Retrieves a list of all active projects from the given REPO.&quot;&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
 &lt;h2&gt;The SQLite Implementation  &lt;a id=&quot;the-sqlite-implementation&quot; class=&quot;anchor&quot; href=&quot;#the-sqlite-implementation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org64c5ec1&quot;&gt;
 &lt;p&gt;
Finally, here is the concrete SQLite implementation using Artanis. this
is completely decoupled from the rest of the application logic.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define-module&lt;/span&gt; ( &lt;span class=&quot;org-type&quot;&gt;lucidplan&lt;/span&gt; sqlite project)
                &lt;span class=&quot;org-builtin&quot;&gt;#:declarative?&lt;/span&gt; #t
                &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (srfi srfi-9)
                &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (kracht prelude)
                &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (artanis db)
                &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (lucidplan sqlite util)
                &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (lucidplan domain project)
                &lt;span class=&quot;org-builtin&quot;&gt;#:export&lt;/span&gt; (make-sqlite-project-repository))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;--- Artanis + SQLite implementation ---&lt;/span&gt;
( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;make-sqlite-project-repository&lt;/span&gt; rc)
        ( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;columns&lt;/span&gt;
                '(id human-id
                     title
                     url
                     vcs-url
                     description
                     created-at
                     updated-at
                     deleted-at))

        ( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;get-projects&lt;/span&gt;)
                ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((query (format #f
                                       &lt;span class=&quot;org-string&quot;&gt;&quot;SELECT ~a&lt;/span&gt;
 &lt;span class=&quot;org-string&quot;&gt;                   FROM project WHERE deleted_at IS NULL&lt;/span&gt;
 &lt;span class=&quot;org-string&quot;&gt;                   ORDER BY human_id ASC&quot;&lt;/span&gt;
                                      (symbols-&gt;sql-columns-list columns)))
                       (_ (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;get-projects query:\n\t~a\n&quot;&lt;/span&gt; query))
                       (rows ( &lt;span class=&quot;org-keyword&quot;&gt;map&lt;/span&gt; sql-row-&gt;scheme-alist
                                  (DB-get-all-rows (DB-query (DB-open rc) query))))
                       (_ (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;get-projects rows: ~a\n&quot;&lt;/span&gt;
                                    (length rows))))
                  rows))

        (mk-project-repository  &lt;span class=&quot;org-builtin&quot;&gt;#:get-projects-proc&lt;/span&gt; get-projects))&lt;/pre&gt;

 &lt;p&gt;
A condensed example with keyword arguments:
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;The DSL (notice how arity is clean)&lt;/span&gt;
(define-repo-method get-jobs repo-get-jobs
                   &lt;span class=&quot;org-string&quot;&gt;&quot;Retrieves a list of active jobs from the given REPO.&quot;&lt;/span&gt;)

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;SQLite implementation&lt;/span&gt;
( &lt;span class=&quot;org-keyword&quot;&gt;define*&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;get-jobs&lt;/span&gt;  &lt;span class=&quot;org-builtin&quot;&gt;#:key&lt;/span&gt; limit offset)
  ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((query (format #f
                  &lt;span class=&quot;org-string&quot;&gt;&quot;SELECT ~a FROM job&lt;/span&gt;
 &lt;span class=&quot;org-string&quot;&gt;                 ORDER BY created_at DESC LIMIT ~a OFFSET ~a&quot;&lt;/span&gt;
                 (symbols-&gt;sql-columns-list columns) limit offset))
         (_ (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;get-jobs query:\n\t~a\n&quot;&lt;/span&gt; query))
         (rows ( &lt;span class=&quot;org-keyword&quot;&gt;map&lt;/span&gt; sql-row-&gt;scheme-alist
                    (DB-get-all-rows (DB-query (DB-open rc) query))))
         (_ (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;get-jobs rows: ~a\n&quot;&lt;/span&gt;
                      (length rows))))
    rows))&lt;/pre&gt;

 &lt;p&gt;
Using it can look like
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt;
  (job-repo (make-sqlite-job-repository rc))
  (jobs (get-jobs job-repo  &lt;span class=&quot;org-builtin&quot;&gt;#:limit&lt;/span&gt; 50  &lt;span class=&quot;org-builtin&quot;&gt;#:offset&lt;/span&gt; 0))
.......)&lt;/pre&gt;

 &lt;p&gt;
I believe I have something really powerful cooking here, but I know
there is always room for improvement.
&lt;/p&gt;

 &lt;p&gt;
 &lt;b&gt;What do you all think?&lt;/b&gt; How would you go about improving this? I’m
entirely open to criticism, feedback, and brainstorming!
&lt;/p&gt;

 &lt;p&gt;
Thanks for reading this :)
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content><source><title>jointhefreeworld</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 269: Portable Test Definitions</title><link href="https://srfi.schemers.org/srfi-269/" rel="alternate"/><id>https://srfi.schemers.org/srfi-269/</id><updated>2026-04-02T12:00:00-08:00</updated><author><name>Andrew Tropin and Ramin Honary</name></author><content type="html">SRFI 269 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;This SRFI defines a portable API for test definitions that is
decoupled from test execution and reporting.  It provides three
primitives: the universal &lt;code&gt;is&lt;/code&gt; macro for
assertions, &lt;code&gt;test&lt;/code&gt; for grouping assertions into
independently executable units, and &lt;code&gt;suite&lt;/code&gt; for organizing
tests into hierarchies.  Tests and suites can carry user-provided
metadata to adjust the behavior of a test runner, for example, to
select tests by tags or to enforce timeout values.  The API is tiny,
yet capable and flexible.  By focusing on the definition and leaving
execution semantics to test runners, this SRFI offers a common ground
that can reduce fragmentation among testing libraries.&lt;/p&gt;

&lt;p&gt;Unlike side-effect-driven testing frameworks (e.g. SRFI-64),
this API produces first-class runtime entities, making it easy to
filter, schedule, wrap them in exception guards and continuation
barriers, run in arbitrary order, and re-run dynamically generated
test subsets.  In addition to the usual CLI test runners, it enables
runtime-friendly test runners that integrate well with highly
interactive development workflows inside REPLs and IDEs, significantly
increasing control over test execution and shortening the feedback
loop.&lt;/p&gt;

&lt;p&gt;To bridge the test definitions and test runners, the SRFI specifies
a message-passing programming interface, and test loading and
execution semantics recommendations for test runner implementers.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Andy Wingo: wastrelly wabbits</title><link href="https://wingolog.org/archives/2026/03/31/wastrelly-wabbits" rel="alternate"/><id>https://wingolog.org/archives/2026/03/31/wastrelly-wabbits</id><updated>2026-03-31T20:34:23Z</updated><author><name>Andy Wingo</name></author><content type="html">&lt;div&gt;&lt;div&gt;&lt;p&gt;Good day!  Today (tonight), some notes on the last couple months of
&lt;a href=&quot;https://codeberg.org/andywingo/wastrel/&quot;&gt;Wastrel&lt;/a&gt;, my ahead-of-time
WebAssembly compiler.&lt;/p&gt;&lt;p&gt;Back in the beginning of February, I showed &lt;a href=&quot;https://wingolog.org/archives/2026/02/06/ahead-of-time-wasm-gc-in-wastrel&quot;&gt;Wastrel running programs
that use garbage
collection&lt;/a&gt;,
using an embedded copy of the &lt;a href=&quot;https://github.com/wingo/whippet&quot;&gt;Whippet
collector&lt;/a&gt;, specialized to the types
present in the Wasm program.  But, the two synthetic GC-using programs I
tested on were just ported microbenchmarks, and didn’t reflect the
output of any real toolchain.&lt;/p&gt;&lt;p&gt;In this cycle I worked on compiling the output from the &lt;a href=&quot;https://spritely.institute/hoot/&quot;&gt;Hoot
Scheme-to-Wasm compiler&lt;/a&gt;.  There were
some interesting challenges!&lt;/p&gt;&lt;h3&gt;bignums&lt;/h3&gt;&lt;p&gt;When I originally wrote the Hoot compiler, it targetted the browser,
which already has a bignum implementation in the form of
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility&quot;&gt;BigInt&lt;/a&gt;,
which &lt;a href=&quot;https://wingolog.org/archives/2019/05/23/bigint-shipping-in-firefox&quot;&gt;I worked on back in the
day&lt;/a&gt;.
Hoot-generated Wasm files use host bigints via &lt;tt&gt;externref&lt;/tt&gt; (though
&lt;a href=&quot;https://wingolog.org/archives/2023/03/20/a-world-to-win-webassembly-for-the-rest-of-us#:~:text=common%20struct%20supertype&quot;&gt;wrapped in structs to allow for hashing and
identity&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;In Wastrel, then, I implemented the imports that implement bignum
operations: addition, multiplication, and so on.  I did so using
&lt;a href=&quot;https://gmplib.org/repo/gmp/file/tip/mini-gmp/README&quot;&gt;mini-gmp&lt;/a&gt;, a
stripped-down implementation of the workhorse GNU multi-precision
library.  At some point if bignums become important, this gives me the
option to link to the full GMP instead.&lt;/p&gt;&lt;p&gt;Bignums were the first managed data type in Wastrel that wasn’t defined
as part of the Wasm module itself, instead hiding behind &lt;tt&gt;externref&lt;/tt&gt;, so
I had to add a facility to &lt;a href=&quot;https://wingolog.org/archives/2026/02/18/two-mechanisms-for-dynamic-type-checks&quot;&gt;allocate type
codes&lt;/a&gt;
to these “host” data types.  More types will come in time: weak maps,
ephemerons, and so on.&lt;/p&gt;&lt;p&gt;I think bignums would be a great proposal for the Wasm standard, similar
to &lt;a href=&quot;https://github.com/WebAssembly/stringref&quot;&gt;stringref&lt;/a&gt; ideally
(&lt;a href=&quot;https://wingolog.org/archives/2023/10/19/requiem-for-a-stringref&quot;&gt;sniff!&lt;/a&gt;),
possibly in an &lt;a href=&quot;https://github.com/WebAssembly/js-string-builtins/blob/main/proposals/js-string-builtins/Overview.md&quot;&gt;attenuated
form&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;exception handling&lt;/h3&gt;&lt;p&gt;Hoot used to emit a &lt;a href=&quot;https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md&quot;&gt;pre-standardization form of exception
handling&lt;/a&gt;,
and hadn’t gotten around to updating to the &lt;a href=&quot;https://wingolog.org/archives/2026/03/10/nominal-types-in-webassembly&quot;&gt;newer
version&lt;/a&gt;
that was standardized last July.  I updated Hoot to emit the newer kind
of exceptions, as it was easier to implement them in Wastrel that way.&lt;/p&gt;&lt;p&gt;Some of the problems &lt;a href=&quot;https://cfallin.org/blog/2025/11/06/exceptions/&quot;&gt;Chris Fallin contended with in
Wasmtime&lt;/a&gt; don’t apply
in the Wastrel case: since the set of instances is known at
compile-time, we can statically allocate type codes for exception tags.
Also, I didn’t really have to do the back-end: I can just use &lt;a href=&quot;https://man7.org/linux/man-pages/man3/longjmp.3.html&quot;&gt;&lt;tt&gt;setjmp&lt;/tt&gt;
and &lt;tt&gt;longjmp&lt;/tt&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This whole paragraph was meant to be a bit of an aside in which I
briefly mentioned why just using &lt;tt&gt;setjmp&lt;/tt&gt; was fine.  Indeed, because
Wastrel never re-uses a temporary, relying entirely on GCC to “re-use”
the register / stack slot on our behalf, I had thought that I didn’t
need to worry about the “volatile problem”.  From the C99 specification:&lt;/p&gt;&lt;blockquote&gt; [...] values of objects of automatic storage duration that
are local to the function containing the invocation of the corresponding
setjmp macro that do not have volatile-qualified type and have been
changed between the setjmp invocation and longjmp call are
indeterminate.  &lt;/blockquote&gt;&lt;p&gt;My thought was, though I might set a value between &lt;tt&gt;setjmp&lt;/tt&gt; and
&lt;tt&gt;longjmp&lt;/tt&gt;, that would only be the case for values whose lifetime did
not reach the &lt;tt&gt;longjmp&lt;/tt&gt; (i.e., whose last possible use was before the
jump).  Wastrel didn’t introduce any such cases, so I was good.&lt;/p&gt;&lt;p&gt;However, I forgot about &lt;tt&gt;local.set&lt;/tt&gt;: mutations of locals (ahem, &lt;i&gt;objects
of automatic storage duration&lt;/i&gt;) in the source Wasm file could run afoul
of this rule.  So, because of writing this blog post, I went back and
did an analysis pass on each function to determine the set of locals
which are mutated inside the body of a &lt;tt&gt;try_table&lt;/tt&gt;.  Thank you, rubber duck readers!&lt;/p&gt;&lt;h3&gt;bugs&lt;/h3&gt;&lt;p&gt;Oh my goodness there were many bugs.  Lacunae, if we are being generous;
things not implemented quite right, which resulted in errors either when
generating C or when compiling the C.  The &lt;a href=&quot;https://wingolog.org/archives/2026/02/09/six-thoughts-on-generating-c&quot;&gt;type-preserving translation
strategy&lt;/a&gt;
does seem to have borne fruit, in that I have spent very little time in
GDB: once things compile, they work.&lt;/p&gt;&lt;h3&gt;coevolution&lt;/h3&gt;&lt;p&gt;Sometimes Hoot would use a browser facility where it was convenient, but
for which in a better world we would just do our own thing.  Such was the
case for the &lt;tt&gt;number-&gt;string&lt;/tt&gt; operation on floating-point numbers: we
did something &lt;a href=&quot;https://codeberg.org/spritely/hoot/src/branch/main/reflect-js/reflect.js#L817-L828&quot;&gt;awful but
expedient&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I didn’t have this facility in Wastrel, so instead we moved to do
float-to-string conversions &lt;a href=&quot;https://codeberg.org/spritely/hoot/src/branch/main/lib/hoot/write.scm#L75-L208&quot;&gt;in
Scheme&lt;/a&gt;.
This turns out to have been a good test for bignums too; the &lt;a href=&quot;https://doi.org/10.1145/231379.231397&quot;&gt;algorithm
we use&lt;/a&gt; is a bit dated and relies
on bignums to do its thing.  The move to Scheme also allows for printing
floating-point numbers in other radices.&lt;/p&gt;&lt;p&gt;There are a few more Hoot patches that were inspired by Wastrel, about
which more later; it has been good for both to work on the two at the
same time.&lt;/p&gt;&lt;h3&gt;tail calls&lt;/h3&gt;&lt;p&gt;My plan for Wasm’s
&lt;a href=&quot;https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-control-mathsf-return-call-x&quot;&gt;&lt;tt&gt;return_call&lt;/tt&gt;&lt;/a&gt;
and friends was to use the new &lt;tt&gt;musttail&lt;/tt&gt; annotation for calls, which
has been in clang for a while and was recently added to GCC.  I was
careful to &lt;a href=&quot;https://wingolog.org/archives/2026/02/09/six-thoughts-on-generating-c#:~:text=for%20ABI%20and%20tail%20calls%2C%20perform%20manual%20register%20allocation&quot;&gt;limit the number of function
parameters&lt;/a&gt;
such that no call should require stack allocation, and therefore a
compiler should have no reason to reject any particular tail call.&lt;/p&gt;&lt;p&gt;However, there were bugs.  Funny ones, at first: &lt;a href=&quot;https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124533&quot;&gt;attributes applying to
a preceding label instead of the following
call&lt;/a&gt;, or &lt;a href=&quot;https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124532&quot;&gt;the need
to insert &lt;tt&gt;if (1)&lt;/tt&gt; before the tail
call&lt;/a&gt;.  More dire
ones, in which &lt;a href=&quot;https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124534&quot;&gt;tail callers inlined into &lt;i&gt;their&lt;/i&gt; callees would cause
the tail calls to
fail&lt;/a&gt;, worked
around with judicious application of &lt;tt&gt;noinline&lt;/tt&gt;.  Thanks to GCC’s Andrew
Pinski for help debugging these and other issues; with GCC things are
fine now.&lt;/p&gt;&lt;p&gt;I did have to change the code I emitted to return “top types only”: if
you have a function returning type T, you can tail-call a function
returning U if U is a subtype of T, but there is &lt;a href=&quot;https://codeberg.org/andywingo/wastrel/issues/25&quot;&gt;no nice way to encode
this into the C type
system&lt;/a&gt;.  Instead, we
return the top type of T (or U, it’s the same), e.g. &lt;tt&gt;anyref&lt;/tt&gt;, and
insert downcasts at call sites to recover the precise types.  Not so
nice, but it’s what we got.&lt;/p&gt;&lt;p&gt;Trying tail calls on clang, I ran into a funny restriction: clang not
only requires that return types match, but requires that tail caller and
tail callee have the same parameters as well.  I can see why they did
this (it requires no stack shuffling and thus such a tail call is always
possible, even with 500 arguments), but it’s not the design point that I
need.  Fortunately there are discussions about &lt;a href=&quot;https://discourse.llvm.org/t/experience-with-clang-musttail/89085/7&quot;&gt;moving to a different
constraint&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;scale&lt;/h3&gt;&lt;p&gt;I spent way more time that I had planned to on improving the speed of
Wastrel itself.  My initial idea was to just emit one big C file, and
that would provide the maximum possibility for GCC to just go and do its
thing: it can see everything, everything is static, there are loads of
&lt;tt&gt;always_inline&lt;/tt&gt; helpers that should compile away to single instructions,
that sort of thing.  But, this doesn’t scale, in a few ways.&lt;/p&gt;&lt;p&gt;In the first obvious way, consider &lt;a href=&quot;https://mastodon.social/@wingo/115378481224538009&quot;&gt;whitequark’s
&lt;tt&gt;llvm.wasm&lt;/tt&gt;&lt;/a&gt;.  This
is all of LLVM in one 70 megabyte Wasm file.  Wastrel made a huuuuuuge C
file, then GCC chugged on it forever; 80 minutes at &lt;tt&gt;-O1&lt;/tt&gt;, and I wasn’t
aiming for &lt;tt&gt;-O1&lt;/tt&gt;.&lt;/p&gt;&lt;p&gt;I realized that in many ways, GCC wasn’t designed to be a compiler
target.  The shape of code that one might emit from a Wasm-to-C compiler
like Wastrel is different from that that one would write by hand.  I
even ran into a &lt;a href=&quot;https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124651&quot;&gt;segfault compiling with
-Wall&lt;/a&gt;, because GCC
accidentally recursed instead of iterated in the &lt;tt&gt;-Winfinite-recursion&lt;/tt&gt;
pass.&lt;/p&gt;&lt;p&gt;So, I dealt with this in a few ways.  After many hours spent pleading
and bargaining with different &lt;tt&gt;-O&lt;/tt&gt; options, I bit the bullet and made
Wastrel emit multiple C files.  It will compute a DAG forest of all the
functions in a module, where edges are direct calls, and go through that
forest, &lt;a href=&quot;https://codeberg.org/andywingo/wastrel/src/branch/main/module/wastrel/partitions.scm#L436&quot;&gt;greedily consuming (and possibly splitting) subtrees until we
have “enough” code to split out a partition&lt;/a&gt;, as measured by number of
Wasm instructions.  They say that &lt;tt&gt;-flto&lt;/tt&gt; makes this a fine approach,
but one never knows when a translation unit boundary will turn out to be
important.  I compute needed symbol visibilities as much as I can so as
to declare functions that don’t escape their compilation unit as
&lt;tt&gt;static&lt;/tt&gt;; who knows if this is of value.  Anyway, this partitioning
introduced no performance regression in my limited tests so far, and
compiles are much much much faster.&lt;/p&gt;&lt;h3&gt;scale, bis&lt;/h3&gt;&lt;p&gt;A brief observation: Wastrel used to emit indented code, because it
could, and what does it matter, anyway.  However, consider Wasm’s
&lt;a href=&quot;https://webassembly.github.io/spec/core/valid/instructions.html#xref-syntax-instructions-syntax-instr-control-mathsf-br-table-l-ast-l-n&quot;&gt;&lt;tt&gt;br_table&lt;/tt&gt;&lt;/a&gt;:
it takes an array of &lt;i&gt;n&lt;/i&gt; labels and an integer operand, and will branch
to the &lt;i&gt;n&lt;/i&gt;th label, or the last if the operand is out of range.  To set
up a label in Wasm, you make a block, of which there are a handful of
kinds; the label is visible in the block, and for &lt;i&gt;n&lt;/i&gt; labels, the
&lt;tt&gt;br_table&lt;/tt&gt; will be the most nested expression in the &lt;i&gt;n&lt;/i&gt; nested blocks.&lt;/p&gt;&lt;p&gt;Now consider that block indentation is proportional to &lt;i&gt;n&lt;/i&gt;.  This means,
the file size of an indented C file is quadratic in the number of branch
targets of the &lt;tt&gt;br_table&lt;/tt&gt;.&lt;/p&gt;&lt;p&gt;Yes, this actually bit me; there are &lt;tt&gt;br_table&lt;/tt&gt; instances with tens of
thousands of targets.  No, wastrel does not indent any more.&lt;/p&gt;&lt;h3&gt;scale, ter&lt;/h3&gt;&lt;p&gt;Right now, the long pole in Wastrel is the compile-to-C phase; the
C-to-native phase parallelises very well and is less of an issue.  So,
one might think: OK, you have partitioned the functions in this Wasm
module into a number of files, why not emit the files in parallel?&lt;/p&gt;&lt;p&gt;I gave this a go.  It did not speed up C generation.  From my cursory
investigations, I think this is because the bottleneck is garbage
collection in Wastrel itself; Wastrel is written in Guile, and Guile
still uses the Boehm-Demers-Weiser collector, which does not parallelize
well for multiple mutators.  It’s terrible but I ripped out
parallelization and things are fine.  &lt;a href=&quot;https://jorts.horse/@migratory/116279275172476524&quot;&gt;Someone on Mastodon suggested
&lt;tt&gt;fork&lt;/tt&gt;&lt;/a&gt;; they’re not
wrong, but also not Right either.  I’ll just keep this as a nice test
case for the Guile-on-Whippet branch I want to poke later this year.&lt;/p&gt;&lt;h3&gt;scale, quator&lt;/h3&gt;&lt;p&gt;Finally, I had another realization: GCC was having trouble compiling the
C that Wastrel emitted, because Hoot had emitted bad WebAssembly.  Not
bad as in “invalid”; rather, “not good”.&lt;/p&gt;&lt;p&gt;There were two cases in which Hoot emitted ginormous (technical term)
functions.  One, for an odd debugging feature: Hoot does a CPS transform
on its code, and allocates return continuations on a stack.  This is a
gnarly technique but it gets us delimited continuations and all that
goodness even before stack switching has landed, so it’s here for now.
It also gives us a reified return stack of &lt;tt&gt;funcref&lt;/tt&gt; values, which lets
us print Scheme-level backtraces.&lt;/p&gt;&lt;p&gt;Or it would, if we could associate data with a &lt;tt&gt;funcref&lt;/tt&gt;.  Unfortunately
&lt;tt&gt;func&lt;/tt&gt; is not a subtype of &lt;tt&gt;eq&lt;/tt&gt;, so we can’t.  Unless... we pass the
funcref out to the embedder (e.g. JavaScript), and the embedder checks
the funcref for equality (e.g. using &lt;tt&gt;===&lt;/tt&gt;); then we can map a funcref
to an index, and use that index to map to other properties.&lt;/p&gt;&lt;p&gt;How to pass that &lt;tt&gt;funcref&lt;/tt&gt;/index map to the host?  When I initially
wrote Hoot, I didn’t want to just, you know, put the funcrefs of interet
into a table and let the index of a function’s slot be the value in the
key-value mapping; that would be useless memory usage.  Instead, we
emitted functions that took an integer, and which would return a
funcref.  Yes, these used &lt;tt&gt;br_table&lt;/tt&gt;, and yes, there could be tens of
thousands of cases, depending on what you were compiling.&lt;/p&gt;&lt;p&gt;Then to map the integer index to, say, a function name, likewise I
didn’t want a table; that would force eager allocation of all strings.
Instead I emitted a function with a &lt;tt&gt;br_table&lt;/tt&gt; whose branches would
return &lt;tt&gt;string.const&lt;/tt&gt; values.&lt;/p&gt;&lt;p&gt;Except, of course, &lt;a href=&quot;https://wingolog.org/archives/2023/10/19/requiem-for-a-stringref&quot;&gt;stringref didn’t become a
thing&lt;/a&gt;,
and so instead we would end up lowering to allocate string constants as
globals.&lt;/p&gt;&lt;p&gt;Except, of course, Wasm’s idea of what a “constant” is is quite
restricted, so &lt;a href=&quot;https://codeberg.org/spritely/hoot/src/branch/main/module/wasm/lower-globals.scm&quot;&gt;we have a pass that moves non-constant global
initializers to the “start”
function&lt;/a&gt;.
This results in an enormous start function.  The straightforward
solution was to partition global initializations into separate
functions, called by the start function.&lt;/p&gt;&lt;p&gt;For the &lt;tt&gt;funcref&lt;/tt&gt; debugging, the solution was more intricate: firstly,
we represent the &lt;tt&gt;funcref&lt;/tt&gt;-to-index mapping just as a table.  It’s fine.
Then for the side table mapping indices to function names and sources,
we emit DWARF, and attach a special attribute to each “introspectable”
function.  In this way, reading the DWARF sequentially, we reconstruct a
mapping from index to DWARF entry, and thus to a byte range in the Wasm
code section, and thus to source information in the &lt;tt&gt;.debug_line&lt;/tt&gt;
section.  It sounds gnarly but Guile already used DWARF as its own
debugging representation; switching to emit it in Hoot was not a huge
deal, and as we only need to consume the DWARF that we emit, we only
needed some &lt;a href=&quot;https://codeberg.org/spritely/hoot/src/branch/main/reflect-js/reflect.js#L3-L377&quot;&gt;400 lines of
JS&lt;/a&gt;
for the web/node run-time support code.&lt;/p&gt;&lt;p&gt;This switch to data instead of code removed the last really long pole
from the GCC part of Wastrel’s pipeline.  What’s more, Wastrel can now
implement the &lt;tt&gt;code_name&lt;/tt&gt; and &lt;tt&gt;code_source&lt;/tt&gt; imports for Hoot programs
ahead of time: it can parse the DWARF at compile-time, and generate
functions that look up functions by address in a sorted array to return
their names and source locations.  As of today, this works!&lt;/p&gt;&lt;h3&gt;fin&lt;/h3&gt;&lt;p&gt;There are still a few things that Hoot wants from a host that Wastrel
has stubbed out: weak refs and so on.  I’ll get to this soon; my goal is
a proper Scheme REPL.  Today’s note is a waypoint on the journey.  Until
next time, happy hacking!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><source><title>Andy Wingo</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 268: Multidimensional Array Literals</title><link href="https://srfi.schemers.org/srfi-268/" rel="alternate"/><id>https://srfi.schemers.org/srfi-268/</id><updated>2026-03-30T12:00:00-08:00</updated><author><name>Per Bothner (SRFI 163), Peter McGoron (design), John Cowan (editor and steward), and Wolfgang Corcoran-Mathe (implementation)</name></author><content type="html">SRFI 268 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;This is a specification of a lexical syntax
for multi-dimensional arrays. Textually it is an alteration of
&lt;a href=&quot;https://srfi.schemers.org/srfi-163/srfi-163.html&quot;&gt;SRFI 163&lt;/a&gt;, which
is an extension of the
&lt;a href=&quot;https://www.lispworks.com/documentation/HyperSpec/Body/02_dhl.htm&quot;&gt;
Common Lisp array reader syntax&lt;/a&gt;
to handle non-zero lower bounds and optional uniform element types
(compatibly with &lt;a href=&quot;https://srfi.schemers.org/srfi-4&quot;&gt;SRFI 4&lt;/a&gt;
and &lt;a href=&quot;https://srfi.schemers.org/srfi-160&quot;&gt;SRFI 160&lt;/a&gt;).
It can be used in conjunction with
&lt;a href=&quot;https://srfi.schemers.org/srfi-25&quot;&gt;SRFI 25&lt;/a&gt;,
&lt;a href=&quot;https://srfi.schemers.org/srfi-122&quot;&gt;SRFI 122&lt;/a&gt;,
or &lt;a href=&quot;https://srfi.schemers.org/srfi-231&quot;&gt;SRFI 231&lt;/a&gt;.
There are recommendations for output formatting,
&lt;code&gt;read-array&lt;/code&gt; and &lt;code&gt;write-array&lt;/code&gt;
procedures, and a suggested
&lt;code&gt;format-array&lt;/code&gt; procedure.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Idiomdrottning: My Butlerian hypocrisy</title><link href="https://idiomdrottning.org/butlerian-hypocrisy" rel="alternate"/><id>https://idiomdrottning.org/butlerian-hypocrisy</id><updated>2026-03-25T11:48:41+01:00</updated><author><name>Idiomdrottning</name></author><content type="html">&lt;div&gt;&lt;div&gt;&lt;p&gt;In the Butlerian Jihad&lt;small&gt; (from Dune but popularized by many smolnet posters like Alex Schroeder)&lt;/small&gt; we rightly hate bots and scrapers but I’m in a bit of a &lt;a title=&quot;throw stones in a glass house - Wiktionary, the free dictionary&quot; href=&quot;https://en.wiktionary.org/wiki/throw_stones_in_a_glass_house&quot;&gt;glass house&lt;/a&gt; around that, since I’ve made a few scrapers for my own personal use as a way to get &lt;abbr title=&quot;I used to think Atom was a competitor/successor to RSS but now that the 'Atom' name got more asnociated with that janky text editor, and RSS han remained a catchy and distinct name, I prefer to think of Atom as a version of RSS&quot;&gt;RSS Atom&lt;/abbr&gt; feeds out of sites that don’t have feeds. I love scraping and mashing.♥︎ The JS-laden SPA era was a nightmare for me. I hate browsers and server-side styling. I love getting texts from URLs.&lt;/p&gt;&lt;h2 id=&quot;follow-ups&quot;&gt;Follow-ups&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;gemini://carcosa.net/journal/20260326-re-butlerian.gmi&quot;&gt;An Inhabitant in Carcosa responds&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Bad in intent: it is intended to do something unethical, whether that be LLM training, denial of service, privatizing the commons, or immanentizing the eschaton. This is pretty subjective in an “I know it when I see it” kind of way. Scraping for a search index, scraping for a full-text RSS feed, and scraping for LLM training are all the same act as far as the server can tell, but only the last one is /evil/.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Having a full-text RSS feed as a way to not have to deal with ads or paywalls—even when the reasons to not be able to otherwise handle ads and paywalls are 100% a11y issues—goes against the intent of the server owners.&lt;/p&gt;&lt;p&gt;And &lt;a href=&quot;/fun-and-good&quot;&gt;I’m not so sure LLMs are evil&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It may ignore robots.txt, it may lie about being another user-agent&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Have done both those too!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Either bad intent or bad implementation is enough; a bot doesn’t need both to be bad.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;That’s &lt;a title=&quot;Iorist ethics&quot; href=&quot;/iorist&quot;&gt;not exactly my philosophy&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I love the open readable simple web where each document has one URL and you can read it on your own terms. I can’t deal with the junk web.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</content><source><title>Idiomdrottning</title></source></entry></feed>
