HNHacker News
TopNewBestAskShowJobs

_jackdk_

494 karma · joined May 17, 2023

submissionscomments
_jackdk_··on Super ZSNES – GPU Powered SNES Emulator
That's what I did, and you're right that it was catching the rat on ZSNES.
_jackdk_··on You can beat the binary search
Fritz Henglein has done some interesting work on fast sorting/grouping. I think Generic Discrimination Sorting and Partitioning Unshared Data in Linear Time[1] is the main paper. Ed Kmett took those ideas and refined them into the discrimination[2] library for Haskell, and gave a very interesting tech talk about it[3].

[1]: https://dl.acm.org/doi/epdf/10.1145/1411203.1411220

[2]: https://hackage.haskell.org/package/discrimination

[3]: https://www.youtube.com/watch?v=cB8DapKQz-I

_jackdk_··on To my students
Prof. Yorgey has done some great work over the years, and wrote one of my favourite papers*. Good on him for speaking up like this. I saw an engineer from Anthropic speak at my alma mater a little while ago and the overwhelming impression I took away from the session was, "if Anthropic are meant to be the good ones, we're really going to be in for a rough time."

* Monoids: Theme and variations (functional pearl): http://ozark.hendrix.edu/~yorgey/pub/monoid-pearl.pdf

_jackdk_··on Super ZSNES – GPU Powered SNES Emulator
My first playthrough of Chrono Trigger was stopped cold because my PC couldn't send enough simultaneous keypresses to unlock a door.
_jackdk_··on Edit store price tags using Flipper Zero
> PRISM-like mass surveillance behind the scene. These systems are managed by former US IC personnel.

A major supermarket chain in Australia (Coles) is literally a client of Palantir.

https://investors.palantir.com/news-details/2024/Palantir-Pa...

_jackdk_··on 10 years ago, someone wrote a test for Servo that included an expiry in 2026
It's a good idea, I don't know how often it's baked into the build runner by default. And in the Guix openssl-1.1.1l case, it hadn't been done.
_jackdk_··on 10 years ago, someone wrote a test for Servo that included an expiry in 2026
This sort of thing can be a real problem for bootstrappable/reproducible builds, where you want to verify that the tests all pass. For a while, GNU Guix wouldn't bootstrap with tests enabled because it wanted to build openssl-1.1.1l for some reason, and the test suite contained expired certificates. (This was especially bad in a Nix-ish environment, where changing whether or not tests run changes the build command that the derivation uses, which means that you can't turn the tests off without changing the hash of every dependent package.)
_jackdk_··on Game devs explain the tricks involved with letting you pause a game
Carmack wrote a really interesting .plan about this. It seems to be written between Q2 and Q3A, and cites the Windows message queue as a big inspiration:

https://github.com/ESWAT/john-carmack-plan-archive/blob/mast...

_jackdk_··on Ghostty – Terminal Emulator
I don't have specific references for you, but perhaps you could look into how old-school roguelikes packaged their software for distribution. Particularly ones that made the jump to Steam or Itch?
_jackdk_··on Play Aardwolf MUD
Some years ago I wrote Haskell bindings to libtelnet ( https://hackage.haskell.org/package/libtelnet ) and a reflex wrapper around them ( https://hackage.haskell.org/package/reflex-libtelnet ).

Perhaps they are useful to you. If you need dependency bounds relaxed or revised to work on modern GHCs, let me know and I'll take a look.

_jackdk_··on Functional Quadtrees
Here's a 3D version used in the creation of sparse voxel octrees:

https://forceflow.be/2013/10/07/morton-encodingdecoding-thro...

Here's an example from AWS, where lat/long pairs are put into a Z-index, which is used as a DynamoDB sort key, letting you efficiently query for items near a point.

https://aws.amazon.com/blogs/database/z-order-indexing-for-m...

_jackdk_··on Zig's new plan for asynchronous programs
A series of functions all passing the same `io: IO` value around exhibit exactly the behavior of the reader monad.
_jackdk_··on Zig's new plan for asynchronous programs
Let's see if I can do it without going too far off the deep end. I think your description of the _IO type_ as "a description of how to carry out I/O that is performed by a separate system" is quite fair. But that is a property of the IO type, not of monads. A monad in programming is often thought of as a type constructor M (that takes and returns a type), along with some functions that satisfy certain conditions (called the "monad laws").

The `IO` type is a type constructor of one argument (a type), and returns a type: we say that it has kind `Type -> Type`, using the word "kind" to mean something like "the 'type' of a type". (I would also think of the Zig function `std.ArrayList` as a type constructor, in case that's correct and useful to you.) `IO String` is the type of a potentially side-effecting computation that produces a `String`, which can be fed to other `IO`-using functions. `readLine` is an example of a value that has this type.

The Haskell function arrow `(->)` is also a type constructor, but of two arguments. If you provide `(->)` with two types `a` and `b`, you get the type of functions from `a` to `b`:

`(->)` has kind `Type -> Type -> Type`.

`(->) Char` has kind `Type -> Type`.

`(->) Char Bool` has kind `Type`. It is more often written `Char -> Bool`. `isUpper` is an example of a value that has this type.

The partially-applied type constructor `(->) r`, read as the "type constructor for functions that accept `r`", is of the same kind as `IO`: `Type -> Type`. It also turns out that you can implement the functions required by the monad interface for `(->) r` in a way that satisfies the necessary conditions to call it a monad, and this is often called the "reader monad". Using the monad interface with this type constructor results in code that "automatically" passes a value to the first argument of functions being used in the computation. This sometimes gets used to pass around a configuration structure between a number of functions, without having to write that plumbing by hand. Using the monad interface with the `IO` type results in the construction of larger side-effecting computations. There are many other monads, and the payoff of naming the "monad" concept in a language like Haskell is that you can write functions which work over values in _any_ monad, regardless of which specific one it is.

I tried to keep this brief-ish but I wasn't sure which parts needed explanation, and I didn't want to pull on all the threads and make a giant essay that nobody will read. I hope it's useful to you. If you want clarification, please let me know.

_jackdk_··on Free applicatives, the handle pattern, and remote systems
That would work if the API we were querying could return results of different types in response to a single query. But we might have a single operation that needs to know a couple of FooIds, a BarId, and a BazId, and they all need to be at least three requests against the remote system.
_jackdk_··on Free applicatives, the handle pattern, and remote systems
> I have queries that depend on responses of preceding queries , how will my runAp_ give me this? It probably won’t.

It definitely won't, which is what I was trying to get at with the discussion of monads and data dependencies. Applicatives by definition cannot have one "effectful" computation depend on the result of another. You could do a large bunch of parallel work until you need to pass a result into a function that decides what additional work to perform, at which point you need a monad. More advanced frameworks like Haxl apparently make this distinction explicit, so your computation proceeds as a sequence of batched parallel options, combining as much work as possible.

_jackdk_··on Free applicatives, the handle pattern, and remote systems
This is a really good question. If you write all the queries directly in Haskell, you get an IO action which you can't inspect: all you can do is execute it and see what it does. It might make requests, it might repeat requests it didn't need to make, it could do literally anything else.

Other programming traditions also have this pattern of inventing minilanguages and interpreters for them; regular expressions are by far the most successful example. You could hand-roll string matching by writing your matching functions by hand, but it's often much easier to ask a regex library to run an interpreter over a string describing the pattern to match.

In Haskell, it's really cheap to invent data structures, so using the same language to describe the work is quite convenient. Laziness also means you almost never materialise the entire intermediate "work to be done" structure - you build little bits as the interpreter demands them. So it doesn't feel as heavyweight as an eDSL in some other language.

_jackdk_··on Australia widens teen social media ban to YouTube, scraps exemption
I was in Melbourne Central the other day and there were big ads up for identity verification platforms, where consumer brands normally put up their ads. That'll prime the brand recognition for everyone so that when the identity checks come in, people will feel more comfortable complying.
_jackdk_··on Falsify: Hypothesis-Inspired Shrinking for Haskell (2023)
This is the key sentence:

> The key insight of the Hypothesis library is that instead of shrinking generated values, we instead shrink the samples produced by the PRNG.

Hedgehog loses shrink information when you do a monadic bind (Gen a -> (a -> Gen b) -> Gen b). Hypothesis parses values out of the stream of data generated by the PRNG, so when it "binds", you are still just consuming off that stream of random numbers, and you can shrink the stream to shrink the generated values.

Here is a talk that applies the Hypothesis idea to test C++: https://www.youtube.com/watch?v=C6joICx1XMY . Discussion of PBT implementation approaches begins at 6:30.

_jackdk_··on Concurrency in Haskell: Fast, Simple, Correct
The interaction of laziness and purity means that the memory costs are not always what you think. Purity means that it's a lot safer to share structure between old and new versions of a data structure where an imperative language would have to do defensive copying, and laziness means that you can incrementally amortise the cost of expensive rebalancing operations (Okasaki is the standard reference for this).
_jackdk_··on Concurrency in Haskell: Fast, Simple, Correct
From the footnotes:

> It gets weirder: in Haskell, exceptions can be thrown to other threads!

What's really interesting is that because of purity, you have to have asynchronous exceptions otherwise you give up a lot of modularity. At least that's what Simons Marlow and Peyton Jones argue in Asynchronous Exceptions in Haskell (2006): https://www.microsoft.com/en-us/research/wp-content/uploads/...

> While the semi-asynchronous approach avoids breaking synchronization abstractions, it is non-modular in that the target code must be written to use the signalling mechanism. Worse still (for us), the semi-asynchronous approach is simply incompatible with a purely-functional language, such as Concurrent Haskell. The problem is that polling a global flag is not a functional operation, yet in a Concurrent Haskell program, most of the time is spent in purely-functional code. On the other hand, since there is absolutely no problem with abandoning a purely-functional computation at any point, asynchronous exceptions are safe in a functional setting. In short, in a functional setting, fully-asynchronous exceptions are both necessary and safe — whereas in an imperative context fully-asynchronous exceptions are not the only solution and are unsafe.

If you can read PLTese, it's really quite a nice paper.

_jackdk_··on Functors, Applicatives, and Monads
I think you don't have to teach people to program with `join`, but just that `m >>= f = join (fmap f) m`. It explains away the "get a value out" question but teaches the most common function from the interface.
_jackdk_··on Functors, Applicatives, and Monads
An intuition of monads built on "flattening" nested layers of `m` is easier to teach and works for more monads.
_jackdk_··on Functors, Applicatives, and Monads
I agree. The "container" intuition for Monads leaves you stuck when you try to contemplate IO (or even Promises, these days), because the "bind" operator looks like it does something impossible: extract "the" `a` from the `IO a`, when you have no idea what it is. (Trust me, I spent a long time stuck at this point.) Better to think of Monad as "Applicative + join" (you need Applicative to get `pure`).

If you think of Monads in terms of `fmap` + `join :: Monad m => m (m a) -> m a`, then you don't need to imagine an "extraction" step and your intuition is correct across more instances. Understanding `join` gives you an intuition that works for all the monads I can think of, whereas the container intuition only works for `Maybe` or `Either e` (not even `[]`, even though it _is_ a container). You can define each of `>>=`/`join`/`>=>` in terms of `pure` + any of the other two, and it is an illuminating exercise to do so. (That `class Monad` defines `>>=` as its method is mostly due to technical GHC reasons rather than anything mechanical.)

_jackdk_··on How Copyover MUD Servers Worked
Cool. What's the best way to reach you? I could join the LOTJ Discord and ping you there, perhaps?
_jackdk_··on How Copyover MUD Servers Worked
So the original versions were even simpler than I knew! I'd like to add this detail to the article. How would you like to be credited?
_jackdk_··on NixOS and Portable Executables
I'm trying to match the EGA colour palette for most if not all of my colour selections, and #555-on-#fff passes WCAG AAA requirements for body text. If I make it #000-on-#fff, I struggle to find good ways to differentiate inline `code` sections.

As for text size, the CSS expresses no opinion: I'm expecting your user agent to act in your best interest.

Do you have any suggestions?

_jackdk_··on NixOS and Portable Executables
Seconded. Despite sounding like it's only a tool for games, `steam-run` is very useful for generally running foreign binaries on NixOS. There's also `nix-ld`: https://github.com/nix-community/nix-ld
_jackdk_··on NixOS and Portable Executables
The post title has been mangled, perhaps by the title simplifier. The "actually" in the title is important - the post is about Justine Tunney's work on "actually portable executables" (https://justine.lol/ape.html). Without it, it sounds like it refers to standard Microsoft "Portable Executable" (PE) format binaries.
_jackdk_··on How Copyover MUD Servers Worked
That's so cool. Have you written about the MUD's history and technical evolution anywhere? If not, would you be interested in collaborating on an article like that?
_jackdk_··on How Copyover MUD Servers Worked
Thanks for bringing this up. I actually had a section on LPMuds in an earlier draft, but took it out because I didn't think I could do it justice. I also wanted to focus more on the Unix stuff. My friends and I tended to play DIKU derivatives, so I was never intimately familiar with LPMuds' capabilities.

I hear that class/skill variety was often greater on LPMuds because it was so much easier to code up custom behaviour. Do you know of any especially good articles on LPMuds class (in the OO sense)/object hierarchies and the software architecture of mudlibs?

← PreviousPage 3 of 4Next →