I’ve been very impressed by the Cosmopolitan Libc project
and the αcτµαlly pδrταblε
εxεcµταblε file format that makes it all possible. Building a crazy
polyglot binary that works on two architectures and half-a-dozen
operating systems is one thing, but Mozilla’s Llamafile
project showed that APEs were more than just a cool hack: it’s stunning
that I just download a reasonably smart LLM to my computer,
chmod +x
it, and begin a conversation. LLM use-cases aside,
single-file dependency-free programs that work basically anywhere are
just a great thing to be able to stick on a USB stick.
But APEs have been a little finicky for me. I run NixOS as my primary operating system, and
sometimes an APE will refuse to launch, or I’ll need to pass
--assimilate
to it and permanently turn it into an x86-64
Linux binary before it’ll work.
The Cosmopolitan project, of course, has a couple of answers ready.
One is to install a system-wide APE loader separate from any
one binary and register it with binfmt_misc
;
the other is to patch the
kernel so it can natively detect APEs. I don’t want to wait for a
full kernel compile each time I need to update, so until the patch lands
in mainline binfmt_misc
is the way to go.
I have set up a Nix Flake at https://git.sr.ht/~jack/cosmo.nix
to hold my experiments joining the Nix and Cosmopolitan universes. For
now, it has convenient NixOS options to register the APE loader with
binfmt_misc
:`
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
# Import cosmo.nix and plumb our nixpkgs rev through it
cosmo-nix = {
url = "sourcehut:~jack/cosmo.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ nixpkgs }: {
nixosConfigurations.myMachine = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# Include the cosmo.nix module...
inputs.cosmo-nix.nixosModules.default
# ...and register the ape-loader with binfmt_misc
{ programs.ape-loader.binfmt = true; }
# Your other NixOS config here.
];
}
}
}
Not bad for an evening’s hacking! I hope to take it further at some
point in the future: I’d like to build the loader itself from a known
bootstrap path rather than fetching a binary, and I’d especially love to
be able to do the same with Cosmopolitan Libc and cosmocc
. I’m
a big fan of bootstrappable
builds, and reliable building of ultraportable binaries from a
documented bootstrap path would be an incredibly cool achievement. I
currently get so much useful stuff out of nix develop
— all
my build dependencies, pre-commit hooks,
useful CI targets, and more — and I have projects in mind where I want
Cosmopolitan Libc to be a “tier 1” platform. Nix-based access to a
cosmocc
toolchain and all cosmocc
-built build
dependencies would make that so much easier.
Haskell’s expressive type system means that type signatures can carry
a lot of information. Haskell’s polymorphism means that you sometimes
write functions that work across an enormous range of types, and are
left wondering “what do I actually call my variables?”. It is often the
case that there’s nothing to say beyond “this variable is a Functor
”,
or “this variable is a monadic action”, and so a single-letter variable
name is appropriate. An unofficial and largely undocumented convention
has emerged around these variable names, and so I wanted to write them
all down in one place.
It should go without saying that single-letter variable names are not always the answer. Like point-free style, it sometimes obscures more than it helps and people get carried away with it. But when you have a highly polymorphic function and no good words to use, choosing the right letter can convey a surprising amount of meaning.
This dictionary is not and cannot be exhaustive. Variable naming often relies on context to convey information, and shorter variable names should only be used when they make sense in context. That context could be:
(...) =>
context to reference
“nearby” concepts, as in Monoid
and
Monad
;(k, v)
to
reference the key and value of a Map
entry; orposition a u t = u * t + (a * t * t) / 2
is reasonable if
the reader knows you’re talking classical mechanics.With the warnings out of the way, the dictionary is after the jump. The bulk of the dictionary documents type variables, where overly long variable names can blow out complicated type signatures. Important value-level variable names are also documented, and are explicitly labelled as such.
Read more...I have travelled a lot this year, and after yet another trip where I lugged too many things around, I’ve been thinking about ways to cut back. The classic guide for this is onebag.com, which covers a very interesting mix of techniques and some carefully-chosen lightweight gear that will take you to the farthest corners of the map. Perma-nomad Vitalik Buterin has his own take on living out of a 40L backpack; one of his key points is to run everything you can off of USB-C. The benefits should be obvious: you cut down the number of charging cables you need to carry and your power bank can recharge any of your devices. While I’m a bit of a luddite, I can see a lot of people travelling with at least a laptop and phone, and possibly also a tablet, earbuds, and/or a smartwatch, all of which need power.
Vitalik’s guide mentions a USB-C “wall wart” charger that he uses to power his stuff. I disagree with this choice, at least for international travel: I think you want a desktop USB-C charger that takes an IEC C7 (“figure 8”) cable.
I’m not aware of any good articles that spell out the “desktop charger + replaceable cable” trick and how to actually find a suitable one, so a full explanation, research procedure, and some tentative recommendations are spelled out in laborious detail after the jump.
Read more...I’ve been meaning to write this one for a while, but the announcement of the Ladybird Browser Initiative makes now a particularly good time.
TL;DR: Chrome is eating the web. I have wanted to help fund a serious alternative browser for quite some time, and while Firefox remains the largest potential alternative, Mozilla has never let me. Since I can’t fund Firefox, I’m going to show there’s money in user-funded web browsers by funding Ladybird instead. You should too.
Read more...It’s really easy to misuse lazy I/O (e.g., hGetContents
)
in nontrivial Haskell programs. You can accidentally close a
Handle
before the computation which reads from it has been
forced, and it’s hard to predict exactly when data will be produced or
consumed by IO
actions. Streaming libraries in Haskell
avoid these problems by explicitly interleaving the yielding of data and
execution of effects, as well as helping control the memory usage of a
program by limiting the amount of data “in flight”.
A number of veteran Haskellers have built streaming libraries, and
off the top of my head I’m aware of conduit
,
io-streams
,
iteratee
,
machines
,
pipes
,
streaming
,
and streamly
.
Of those, I think conduit
, pipes
,
streaming
, and streamly
are the most commonly
used ones today. It can be hard to know which library to choose when
there’s so many options, so here is my heuristic:
conduit
); orstreaming
.I’ll explain why after the jump.
Read more...