https://delaybahn.com/en/?fromId=A%3D1%40O%3DK%C3%B6ln+Hbf%4...
Click the "+30 min (28/30 days)" tags to see the delays of the last month.
3,613 karma · joined March 29, 2014
[ my public key: https://keybase.io/nh2; my proof: https://keybase.io/nh2/sigs/Duv6hcXOkjZU5KWzJ8d01yeD7QKmhG9QpVMOb4ZMkeU ]
https://delaybahn.com/en/?fromId=A%3D1%40O%3DK%C3%B6ln+Hbf%4...
Click the "+30 min (28/30 days)" tags to see the delays of the last month.
I also find Haskell's concurrency in practice much easier to reason about than Go's, let me do a pitch:
In Haskell you can just fork a thread and block till it's done. Threaded, "async" logic just looks like blocking serial code (but isn't blocking). I feel like in typical channel-based Go code I have to jump and scroll a lot in the code because of all the message-passing instead of block-scoped "blocking-style" variable use, and that this makes it hard to conclude whether the whole thing terminates or deadlocks.
In Haskell, channels are considered low-level concurrency primitives you should only use when you have no clean high-level primitives for it. This is because they are not "structured" concurrency: When you send something into a channel, it is gone out of your scope, and you now need to track in your brain where it is, and who should consume that thing in the right way ("message-passing").
For example, in Stolon, a high-availability Postgres orchestrator written in Go (https://github.com/sorintlab/stolon), I found the logic for failover with multiple channels and various timeouts very difficult to reason about when investigating failover bugs. I'm pretty sure that would read much easier in Haskell (see below how).
In Haskell, you can start 2, or N, things in parallel, and easily wait till they are done. You can invoke parallel `map` easily.
results <- mapConcurrently f mylist
If f throws on any element, the whole map throws, and other threads get cancelled automatically as expected.You can get bounded, steaming parallelism, easily.
You can set time limits to function calls writing
timeout 1000 (myIoFunction ...)
You can cancel any thread or computation, at any time. The same timeout function can cancel blocking IO operations, such as reading from the terminal or sockets, without having pass around `Context` objects like in Go (which, if you forget it, just makes things hang or deadlock).You wrap the 2 words "timeout 1000" around your function and done.
Concurrency _composes_ in Haskell. You can write
res :: Maybe (Maybe a) < timeout a (timeout b (myIoFunction ...))
and the returned type tells you cleanly at which level the cancellation occured (no mixing into the same `error` type.You can build trees of parallel operations that live and die together.
And there are no data races (because mutability is a very explicit thing), and I'm not even mentioning STM here (which allows you to do database-style transactions across variables) because that's already pointed out in another post.
As a composed example, in Haskell you can write:
timeout 1000 (race (downloadUrl ...) (forever (putStrLn "Still loading ...")))
and that will do exactly what you think it should, with correct Ctrl+C cancellability, and good developer ergonomics.If you enjoy concurrency, give Haskell a shot!
I believe Go didn't originally have it, and added it in 2020, 14 years after Haskell.
> integer literals become i32, float literals become f32
Don't use the shitty small sizes that have introduced countless bugs over the last decades, as a language default.
Especially if you care about correctness.
i32 is all over the examples.
Use 64 bits, like Python and Haskell; even JavaScript and thus TypeScript got floats right defaulting to f64.
Killer feature!
> from the past three years [..] the latest I’ve seen were Opus-4.6 and GPT-5.5 struggle a lot with standard GHC Haskell
If your experience is from years ago, I totally get that. For my standards, LLMs were pretty bad before 2026.
I haven't tried any serious LLM Haskell before 2026-02, because it was just not a timesaver.
I had good experiences with Opus-4.6 already on Haskell, such as it having detail knowledge on async exceptions, allowing it to immediately pinpoint difficult bugs that me and other experts missed, e.g. https://github.com/snoyberg/conduit/pull/530
But most of my experience is from Opus >= 4.8. I found it excellent at writing difficult TemplateHaskell and Generics implementations, such as oneshotting Postgres JsonPath queries derived from lens-like field accessors on Haskell types.
Note it's still not great at writing general high-quality "engineering" stuff, e.g. Opus 5.0 writes functions that refer to things out of their scope, such as:
requireFooOr400 :: MyMonad m => Maybe Foo -> m Foo
requireFooOr400 x = case x of
Nothing -> throwHttp400 "Cannot perform [very specific action from the caller]: the inputs have no foo"
Just foo -> return foo
However, that's not a lack of Haskell understanding, and it does that for all languages, e.g. in Python it keeps writing implementation details into API docstrings instead of function body comments.Such as these non-frontend devs?
Does "Square ring" really look jerky/retro?
Opening https://nh2.me/low-fps-spinners/smooth-spinner.html it doesn't matter if I zoom the spinner to 25% or 500%: Despite the 400x difference in pixels redrawn, the "GPU Process" CPU usage in the "Browser" tab of the Chromium Shift+Esc task manager is equally high.
It only scales down the cost when reducing the FPS.
But do really have the CPU/GPU go idle, you need to not use them; the only solution to that is to show still images, aka reduce FPS.
Cannot confirm functional programming being inefficient token-wise, or worse at being generated than other paradigms. Claude is great at Haskell.
The difficult parts about Haskell, such as understanding type checker error messages, are gone thanks to LLMs.
Type-safe, side-effect free code degrades correctness a lot less under heavy LLM action in my experience.
Doing it 30x more frequent than needed costs more, no matter if it's only 1 pixel.
This problem is not isolated to me or to just one machine. Check out the chromium bug about the tab loading spinner, for example. It is a "simple" spinner as well.
Or the Zed editor, which spams screen redraws even when nothing changes at all, so it has high GPU usage for still picture.
It breaks the most fundamental debugging expectations (such as "delete code until problem disappears") if the fundamental, minimal building blocks of a language, when on their own, do random rubbish.
To understand a program that does something, better first understand a program that does nothing.
As a fan of sensible analogies:
You put a salad bowl with vinegar into the fridge and notice that when you do that, the fridge stinks afterwards. You try again without the vinegar, then without the salad. In C++ world, upon receiving the empty bowl, the fridge detonates ("it is not useful"), blowing up your house. That is not OK.
This is controlled by jemalloc settings `dirty_decay_ms`, `muzzy_decay_ms`, and their interaction with `background_thread`.
`dirty_decay_ms` currently defaults to 10 seconds, so it's not that instant.
That is important e.g. for single-threaded programs that start other programs, such as my Python example: If it starts a subprocess before the 10 seconds elapse after `free()`, Python (and jemalloc) do not run, and get no chance to return memory to the OS.
In such cases, either enable `background_thread`, or set the `_decay_` values to `0` to ensure immediate return to the OS upon `free()`. (This costs some performance.)
In our Python program, a bit of numpy processing of large pictures led to 100 GB not being returned to the OS by glibc's default allocator and the machine running out of memory shortly after. With jemalloc's reliable memory return settings, those problems disappear.
Using recursion on unbounded inputs on a programming language that doesn't support that (which are most) is an extremely classical mistake that really should be known to all programmers, especially those of low level languages that care about safety.
Every time you call something recursively you should be thinking "how deep is this?".
From the same makers or others?
On the website I can find no info whether this project is concluded or not.
Good choice in my opinion, as I hadn't even noticed the animation existed until I looked for something that might make the scrolling slow.
Is it the animation at the top?
In contrast to Gerrit and Phabricator, it needs not "Change IDs" inserted in your commits (easier workflow just using git) and "just works" to review whole branches.
It seems to me that "1 PR = 1 commit = 1 review" and "stacked PRs" workflows are just workarounds for not properly having implemented that as Reviewable has. Am I not seeing something?
Reviewable's main drawback is being for Github only and not open source.
It guarantees that pure functions are pure.
https://www.microsoft.com/en-us/research/publication/safe-ha...
https://downloads.haskell.org/ghc/latest/docs/users_guide/ex...
For those that hadn't read yet (on https://aws.amazon.com/service-terms/):
"Certain models" means "only AWS's own trained models" (Nova etc), so not e.g. Bedrock Claude or GPT.
"Certain limits" means they don't defent if the input to the model is the IP.
rename to NodePointer instead
format
Revert "format"
Revert "rename to NodePointer instead"
rename to OptionalNodePtr
woops
update comment
slot renames
more renames
Source: https://github.com/duckdb/duckdb/pull/23605If every Ctrl+S is a commit, it'll go up fast.
"woops"!
But I self-host email for ~20 years, and I have not managed to get rid of Spam without not also getting false positives.
I first used SpamAssistant, in later years Rspamd, but I feel like they are just not good enough. Also I find Rspamd config pretty incomprehensible.
Hosted email like also does not solve this, e.g. GMail filters way much (e.g. important company correspondence leading to orders almost being lost because they landed in our GMail spam, so I had to turn off the spam filter entirely).
My self-hosted email filters too little spam, while GMail etc filter too much (e.g. important company correspondence leading to orders almost being lost because they landed in our GMail spam).