HNHacker News
TopNewBestAskShowJobs

chriswarbo

7,969 karma · joined June 28, 2013

submissionscomments
chriswarbo··on Obsolete Sounds
I love that Amiga emulators (FS/E/Win)UAE have an option to emulate the floppy drive sound. Very nostalgic, but also useful as an indication that something's happening!
chriswarbo··on Hypothesis, Antithesis, synthesis
> thanks to Curry-Howard isomorphism, the full-fidelity mathematical model of a database or web browser are their binaries themselves.

Maybe I'm misunderstanding you, but Curry-Howard is a mapping between mathematical jargon and programming jargon, where e.g. "this is a proof of that proposition using foo logic" maps to "this program has that type in programming language foo".

I don't see how that makes "binaries" a "full-fidelity mathematical model": compilation is (according to Curry-Howard) translating a proof from one system of logic to another. For a binary, the resulting system of logic is machine code, which is an absolutely terrible logic: it has essentially one type (the machine word), which makes every proposition trivial; according to Curry-Howard, your database binary is proof of the proposition corresponding to its type; since the type of every binary is just "some machine words", the proposition that your database binary is a "full-fledged mathematical model" of is essentially just "there exists a machine word". Not very useful; we could optimise it down to "0", which is also a proof that there exists a machine word.

If we assume that you want to prove something non-trivial, then the first thing you would need to do is abstract away from the trivial logic of machine code semantics, by inferring some specific structures and patterns from that binary, then developing some useful semantics which captures those patterns and structures. Then you can start to develop non-trivial logic on those semantics, which will let you state worthwhile propositions. If we apply the Curry-Howard lens to that process, it corresponds to... decompilation into a higher-level language!

tl;dr Curry-Howard tells us that binaries are literally the worst possible representation we could hope for.

chriswarbo··on Hypothesis, Antithesis, synthesis
> But it's still a "blind" fuzzer and it would be nice to write one that gets feedback from code coverage somehow

There have been simplistic attempts at this, e.g. instead of performing 100 tests, just keep going as long as coverage increases.

The Choice Gradient Sampling algorithm from https://arxiv.org/pdf/2203.00652 feels like a nice way to steer generators in a more nuanced way. That paper uses it to avoid discards when rejection-sampling; but I have a feeling it could be repurposed to "reward" based on new coverage instead/as-well.

chriswarbo··on Leanstral: Open-source agent for trustworthy coding and formal proof engineering
> The moment you let the LLM write the tests without understanding them, you may as well just let it write the code directly.

I disagree. Having tests (even if the LLM wrote them itself!) gives the model some grounding, and exposes some of its inconsistencies. LLMs are not logically-omniscient; they can "change their minds" (next-token probabilities) when confronted with evidence (e.g. test failure messages). Chain-of-thought allows more computation to happen; but it doesn't give the model any extra evidence (i.e. Shannon information; outcomes that are surprising, given its prior probabilities).

chriswarbo··on Leanstral: Open-source agent for trustworthy coding and formal proof engineering
> The scientific approach starts with a theory that does it's best to explain some phenomenon

At the risk of stretching the analogy, the LLM's internal representation is that theory: gradient-descent has tried to "explain" its input corpus (+ RL fine-tuning), which will likely contain relevant source code, documentation, papers, etc. to our problem.

I'd also say that a piece of software is a theory too (quite literally, if we follow Curry-Howard). A piece of software generated by an LLM is a more-specific, more-explicit subset of its internal NN model.

Tests, and other real CLI interactions, allow the model to find out that it's wrong (~empiricism); compared to going round and round in chain-of-thought (~philosophy).

Of course, test failures don't tell us how to make it actually pass; the same way that unexpected experimental/observational results don't tell us what an appropriate explanation/theory should be (see: Dark matter, dark energy, etc.!)

chriswarbo··on Leanstral: Open-source agent for trustworthy coding and formal proof engineering
Tests (and type-checkers, linters, formal specs, etc.) ground the model in reality: they show it that it got something wrong (without needing a human in the loop). It's empiricism, "nullius in verba"; the scientific approach, which lead to remarkable advances in a few hundred years; that over a thousand years of ungrounded philosophy couldn't achieve.
chriswarbo··on Separating the Wayland compositor and window manager
Yeah, it took me a while to discover that it was removed from KWin. (I eventually ended up reading the sources). It didn't help that KWin also does 3D effects, so all of my Web searches for "shading" were returning results for "shader" :-(
chriswarbo··on How I write software with LLMs
I'm considering using subagents, as a way to manage context and delegate "simple" tasks to cheaper models (if you want to see tokens burn, watch Opus try fixing a misplaced ')' in a Lisp file!).

I see what you mean w.r.t. different hats; but is it useful to have different tools available? For example, a "planner" having Web access and read-only file access, versus a "developer" having write access to files but no Web access?

chriswarbo··on How I write software with LLMs
> investing energy in formulating a syntactically nice sentence

This seem to be completely subjective; I write syntactically/grammatically "nice" sentences to LLMs, because that's how I write. I would have to "invest energy" to force myself to write in that supposedly "simpler" style.

chriswarbo··on Your phone is an entire computer
I do that with my Pinephone (a powered USB-C hub with ethernet, HDMI, keyboard and mouse; I also plug a proper set of speakers+subwoofer into headphone jack).

Both Phosh and PlasmaMobile turn into a "proper" desktop when "docked" (Gnome-like and KDE-like, respectively).

chriswarbo··on The purpose of Continuous Integration is to fail
Comparing actual outputs against expected ones is the ideal situation, IMHO. My own preference is for property-checking; but hard-coding a few well-chosen values is also fine.

That's made easier when writing (mostly) pure code, since the output is all we have (we're not mutating anything, or triggering other processes, etc. that would need extra checking).

I also think it's important to make sure we're checking the values we actually care about; since those might not be the literal return value of the "function under test". For example, if we're testing that some function correctly populates a table cell, I would avoid comparing the function's result against a hard-coded table, since that's prone to change over time in ways that are irrelevant. Instead, I would compare that cell of the result against a hard-coded value. (Rather than thinking about the individual values, I like to think of such assertions as relating one piece of code to another, e.g. that the "get_total" function is related to the "populate_total" function, in this way...).

The reason I find this important, is that breaking a test requires us to figure out what it's actually trying to test, and hence whether it should have broken or not; i.e. is it a useful signal that requires us to change our approach (the table should look like that!), or is it noise that needs its incidental details updated (all those other bits don't matter!). That can be hard to work out many years after the test was written!

chriswarbo··on The purpose of Continuous Integration is to fail
> a pass where there wasn't coverage

I always feel obliged to point out that we can have 100% coverage without making a single assertion (beware Goodhart's law)

chriswarbo··on The purpose of continuous integration is to fail
I agree. The same can be said for testing too: their main purpose is to find mistakes (with secondary benefits of documenting, etc.). Whenever I see my tests fail, I'm happy that they caught a problem in my understanding (manifested either as a bug in my implementation, or a bug in my test statement).
chriswarbo··on Newcomb's Paradox Needs a Demon
> I believe, that if your definition of a choice stop working if we assume a deterministic Universe, then you need a better definition of a choice. In a deterministic Universe becomes glaringly obvious that all the framework of free will and choice is just an abstraction, that abstract away things that are not really needed to make a decision.

Indeed, I think of concepts like "agency", "choice", "free will", etc. as aspects of a particular sort of scientific model. That sort of model can make good predictions about people, organisations, etc. which would be intractable to many other approaches. It can also be useful in situations that we have more sophisticated models for, e.g. treating a physical system as "wanting" to minimise its energy can give a reasonable prediction of its behaviour very quickly.

That sort of model has also been applied to systems where its predictive powers aren't very good; e.g. modelling weather, agriculture, etc. as being determined by some "will of the gods", and attempting to infer the desires of those gods based on their observed "choices".

It baffles me that some people might think a model of this sort might have any relevance at a fundamental level.

chriswarbo··on Avoiding Trigonometry (2013)
Norman Wildberger takes this to the extreme with Rational Trigonometry https://en.wikipedia.org/wiki/Divine_Proportions:_Rational_T...

It eschews angles entirely, sticking to ratios. It avoids square roots by sticking to "quadrances" (squared distance; i.e. pythagoras/euclidean-distance without taking square roots).

I highly recommend Wildberger's extensive Youtube channels too https://www.youtube.com/@njwildberger and https://www.youtube.com/@WildEggmathematicscourses

He's quite contrarian, so I'd take his informal statements with a pinch of salt (e.g. that there's no such thing as Real numbers; the underlying argument is reasonable, but the grand statements lose all that nuance); but he ends up approaching many subjects from an interesting perspective, and presents lots of nice connections e.g. between projective geometry, linear algebra, etc.

chriswarbo··on Rebasing in Magit
I'm still learning jj, so I'm not sure about jj things that majutsu might be missing, or what git/magit things seem "missing" but are just done differently in jj.

A couple of things I tend to notice:

- In magit, I can run a raw git shell commands by pressing `:`; majutsu doesn't seem to have that, so I use Emacs ordinary `M-!`

- The default view in majutsu (log) isn't as slick as magit's. With magit, I'll routinely open it up to look at the repo status, browse through the diffs (expanding/collapsing), staging/unstaging, etc. With majutsu, most of that requires first opening up the log, then opening up the diff of a commit.

- Staging/unstaging in magit is quite nice. The analogous workflow in jj seems to be splitting/squashing, but that feels clunkier in majutsu.

I've not opened bugs or PRs for these things, since it's mostly vibes and I don't have actual solutions to offer ;-)

EDIT: Oh, I also remembered that `jj` ignores $PAGER and uses its own built-in paging by default. That tries to act like `less`, and doesn't work well in Emacs. It can't use env vars either, unless we set its pager to something like `sh -c "$PAGER"` (see https://docs.jj-vcs.dev/latest/config/#pager ). Since my $PAGER is always `cat`, I've just set that as jj's pager directly too.

chriswarbo··on Rebasing in Magit
> I think having a globally shared buffer state, etc. is an antifeature.

As someone who mostly lives in Emacs, I like it. If I'm away from a machine, I can SSH into it and carry on with whatever I was in the middle of.

It's also nice to set emacsclient as EDITOR, so that e.g. running `git commit` will open up a buffer in the existing Emacs session. This is especially useful since I use shell-mode, and it would be confusing/weird to have new Emacs instances popping up when I'm already in an editor! (They open in a "window" (i.e. pane) in the existing "frame" (i.e. window) instead)

chriswarbo··on Rebasing in Magit
Emacs can certainly be sluggish, but I'm not sure how much that's e.g. inherent to ELisp, or due to synchronous/single-threaded code, or choosing slow algorithms for certain tasks, etc.

For me, the best performance improvement has been handling long lines; e.g. Emacs used to become unusable if it was given a line of around 1MB. Since I run lots of shell-mode buffers, that would happen frustratingly-often. My workaround was to make my default shell a script that pipes `bash` through a pared-down, zero-allocation copy of GNU `fold`, to force a newline after hitting a certain length (crossing a lower threshold would break at the next whitespace; hitting an upper threshold would force a break immediately). That piping caused Bash to think it wasn't interactive, which required another work-around using Expect.

Thankfully the last few versions of Emacs have fixed long-line handling enough for me to get rid of my awful Rube-Goldberg shell!

chriswarbo··on Rebasing in Magit
I've been using magit for years, and it's the reason I avoided giving the jujutsu VCS a try: the `jj` workflow/UI is supposedly much nicer than the `git` workflow/UI; but since I use magit more than bare `git` commands, that wasn't enough to sell me.

I finally gave it a try when I came across the majutsu package, which is a magit-like interface for jujutsu. I recommend it for Emacs/magit users wanting to try `jj`!

chriswarbo··on Relax NG is a schema language for XML (2014)
I think XML fit well into the turn-of-the-millenium zeitgeist: GUIs would hide the verbosity; the proliferation of bespoke tags would map cleanly to OOP representations; middleware could manipulate and transform data generically, allowing anything to plug into anything else (even over the Internet!).

Whilst lots of impressive things were built, the overall dream was always just out of reach. Domain-specific tooling is expensive to produce and maintain, and often gives something that's not quite what we want (as an extreme example, think of (X)HTML generated by Dreamweaver or FrontPage); generic XML processors/editors don't offer much beyond avoiding syntax/nesting errors; so often it was simplest to interact directly with the markup, where the verbosity, namespacing, normalisation, etc. wouldn't be automated-away.

XML's tree model was also leaky: I've worked with many data formats which look like XML, but actually require various (bespoke!) amounts of preprocessing, templating, dereferencing, etc. which either don't fit the XML model (e.g. graphs or DAGs), or just avoid it (e.g. sprinkling custom grammar like `${foo.bar}` in their text, rather than XML elements like `<ref name="foo.bar" />`). Of course, it was hard to predict how those systems would interact with XML features like namespaces, comments, etc. which made generic processing/transforming middleware less plug-and-play. That, plus billion-laugh mitigation, etc. contributed to a downward spiral of quality, where software would not bother supporting the full generality of XML, and only allowed its own particular subset of functionality, written in one specific way that it expected. That made the processors/transformers even less useful; and so on until eventually we just had a bunch of bespoke, incompatible formats again. At which point, many just threw up their hands and switched to JSON, since at least that was simpler, less verbose and easier to parse... depending whether you support comments... and maybe trailing commas...; or better yet, just stick to YAML. Or TOML.....

(My favourite example: at an old job, I maintained an old server that sent orders from our ecommerce site to third party systems, using a standard "cXML" format. Another team built a replacement for it, I helped them by providing real example documents to test with, and eventually the switch was made. Shortly after, customers were receiving dozens of times what they ordered! It turned out that a third-party was including an XML declaration like `<?xml>` at the start of their response, which caused the new system to give a parse failure: it treated that as an error, assumed the order had failed, and retried; over and over again!)

chriswarbo··on The Om Programming Language
> I am always kind of surprised when I go to a landing page for a language and there isn't any actual code.

So, you're not surprised that this Om page has an extensive section called "Examples", right? https://www.om-language.com/#language__examples__

chriswarbo··on Pi – A minimal terminal coding harness
Doesn't need a terminal: run it in RPC mode to send/receive JSON over stdio. That's how the pi-coding-agent Emacs package works, which is the only way I've ever used Pi.

It seems pretty well done: when I added permission requests to the `bash` tool, the "Are you sure y/N" requests started appearing just like they were native to Emacs.

chriswarbo··on Pi – A minimal terminal coding harness
> I still don't get why would you want to use a terminal app to code when you can do all of this through IDE extension which does the same except it is better integrated.

I agree. I tried Gemini CLI for a while, and didn't like how separate I felt from the underlying files: rather than doing minor cleanup myself, the activation energy of switching to a separate editor and opening the same files was too high, so I'd prompt the LLM to it instead. Which was often an exercise in frustration, as it would take many rounds of explanation for such tiny payoffs; maybe even fiddling with system prompts and markdown files, to try and avoid wasting so much time in the future...

I've been using Pi for a few weeks now, and have managed to integrate it quite deeply into Emacs. I run it entirely via RPC mode (JSON over stdio), so I don't really know (or care) about its terminal UI :-)

chriswarbo··on Turing Completeness of GNU find
They explicitly state that using `-execdir` to change the working directory avoids issues with PATH_MAX; though I didn't see any mention of the working directory itself having a limit (which I assume it does, for Linux processes?)
chriswarbo··on Turing Completeness of GNU find
Turing's "On Computable Numbers" paper is credited with inventing the Universal Turing Machine; but really it lays out many remarkable things:

- Undecidability: that there are mathematical/logical questions whose answers cannot be calculated by any (formal/logical/physical) system

- Universal computation: there exist systems which can answer all decidable questions

- Universal Turing Machine: an incredibly simple example of such a universal system

Of course, these are inter-related and inevitable (otherwise they wouldn't be provable!); but at first glance it feels like these could have gone either way: Maybe all questions could be calculated, given sufficient cleverness (as Hilbert expected)? Maybe different systems would be required for different sorts of question? Maybe a universal system would be too outlandishly elaborate to make sense in our universe (as existence proofs often are)?

Yet here we are, discussing multiple ways to perform universal computation with GNU find!

chriswarbo··on Pi – A minimal terminal coding harness
I've pushed the extension to GitHub at https://github.com/Warbo/pi-extensions/tree/master/extension...

The implementation is pretty terrible: a giant string of vibe-coded Emacs Lisp is sent to emacsclient, which performs the actions and sends back a string of JSON.

It's been interesting to iterate on the approach: watching the LLM (in my case Claude) attempting to use the tools; noticing when it struggles or makes incorrect assumptions; and updating the tool, documentation and defaults to better match those expectations.

I've also written some Emacs Lisp which opens Pi and tells it to "Action the request/issue/problem at point in buffer '<current-buffer>'" https://github.com/Warbo/warbo-emacs-d/blob/a13a1e02f5203476...

It feels similar to the file-watching provided by Aider (which uses inotify to spot files containing `# AI!` or `# AI?`), which I've previously used with FIXME and TODO comments in code; but it also works well in non-file things, e.g. error messages and test failures in `shell-mode`, and issues listed in the Emacs UI I wrote for the Artemis bug tracker (Claude just gets the issue number from the current line, and plugs that into a Pi extension I made for Artemis :-) )

chriswarbo··on Pi – A minimal terminal coding harness
I've been using pi via the pi-coding-agent Emacs package, which uses its RPC mode to populate a pair of Markdown buffers (one for input, one for chat), which I find much nicer than the awful TUIs used by harnesses like gemini-cli (Emacs works perfectly well as a TUI too!).

The extensibility is really nice. It was easy to get it using my preferred issue tracker; and I've recently overridden the built-in `read` and `write` commands to use Emacs buffers instead. I'd like to override `edit` next, but haven't figured out an approach that would play to the strengths of LLMs (i.e. not matching exact text) and Emacs (maybe using tree-sitter queries for matches?). I also gave it a general-purpose `emacs_eval`, which it has used to browse documentation with EWW.

chriswarbo··on Pi – A minimal terminal coding harness
> Why is it insecure, well, Pi tells you >No permission popups.

Pi supports permission popups, but doesn't use them by default. Their example extensions show how to do it (add an event listener for `tool_call` events; to block the call put `block: true` in its result).

> there's no secure way to know whether what they're asking to is what they'll actually do

What do you mean? `tool_call` event listeners are given the parameters of the tool call; so e.g. a call to the `bash` tool will show the exact command that will execute (unless we block it, of course).

chriswarbo··on Pi – A minimal terminal coding harness
pi has an RPC mode which just sends/receives JSON lines over stdio (including progress updates, and "UI" things like asking for confirmation, if it's configured for that).

That's how the pi-coding-agent Emacs package interacts with pi; and it's how I write automated tests for my own pi extensions (along with a dummy LLM that emits canned responses).

chriswarbo··on Notes on Clarifying Man Pages
I've never used kubectl, but I just came across https://github.com/andykuszyk/noman.el which is an Emacs interface for browsing the `--help` output of commands:

> I primarily wrote this package to navigate the command line help from kubectl and aws, both of which have nested sub-commands, and quite verbose (and helpful!) command line help.

> Neither of these programs ships with man pages, or similar offline documentation. I find myself consulting the command line help often, but struggling to find the experience very ergonomic.

← PreviousPage 3 of 34Next →