A Haskeller's case for Zig
- title
- A Haskeller's case for Zig
- type
- summary
- summary
- A long-time Haskell user evaluates Zig on three axes โ domain expressiveness, type-system programmability, mean-free path โ and concludes comptime gets you most of Haskell without GC
- parent
- zig
- tags
- zig, haskell, comptime, type-system, language-design
- sources
- zig-functional-programmers
- created
- 2026-04-30
- updated
- 2026-04-30
The author of pure-systems-blog has been writing Haskell for 10+ years and evaluates new languages on three axes:
- How cleanly the language lets you express the program's domain (anything you write that isn't about the domain is noise โ manual memory management is the canonical example).
- What the language gives you for correct-by-construction programs and how programmable the type system is.
- The mean-free-path-language โ how many lines you can write before your understanding of the program diverges from what the program actually does.
Zig scores well on all three, and the post walks through why.
The garbage-collection critique
GC was a defensible tradeoff in 1995 when CPU and memory speeds were comparable. Since then CPU has gotten roughly 10,000ร faster while memory access has barely budged, but languages still assume a 1995 machine. The "forest of pointers into the heap" pattern that GC encourages caps performance.
There's also a cognitive cost the author flags: GC makes it too easy not to think about the machine. A generation of developers grew up never having to. The result is software that is bloated and slow on hardware that is effectively a supercomputer compared to what we had 30 years ago. (Compare peril-of-laziness-lost โ Cantrill making the same charge from a different angle, that LLM coding removes the human-time constraint that used to force simplicity.)
The author cites Stephen Diehl's argument that nobody has the incentive to build a real new language: academics commit career suicide doing the engineering, industry can't fund decade-long projects, hobbyists don't have the time or money. So the field is stuck at a local maximum. Zig is interesting because Andrew Kelley's project "has the courage" to actually try.
Comptime as type-system programming
The author wants Haskell-style type-system programming without paying for GC. Zig's comptime is the mechanism:
newtypeis just a singleton struct:struct PlayerHealth { health: u32 }.- Sum types are tagged unions โ there's even built-in optional syntax, and you can build your own
Maybe(T)as acomptimefunction returning aunion(enum)withvalue: Tandnothingvariants, with amapmethod that pattern-matches on the variant. - Typeclasses are
comptimefunctions that take a type, check it has the required methods (if (!@hasDecl(T, "eql")) @compileError(...)), and return a struct of wrapper functions. The catch is you have to pass the resulting struct around explicitly โEqPoint.eql(a, b)instead ofa == b. That's the typeclass dictionary made manual. The clunkier version (you callEq(Point)at the use site) can be cleaned up by having the type itself derive its own dictionary as apub const Eq = EqClass(@This())field.
The dictionary-passing being explicit is the point, not a wart. Zig's stated philosophy is "no spooky action at a distance." Implicit typeclass dispatch is exactly the kind of action-at-a-distance the language refuses to do, and the author thinks that tradeoff is worth it.
The accidental rediscovery of monads
Zig 0.16 reworked its IO subsystem to an interface design. The example in the release notes:
pub fn main(init: std.process.Init) !void {
const gpa = init.gpa;
const io = init.io;
var http_client: std.http.Client = .{ .allocator = gpa, .io = io };
...
}
The author looks at this and sees a Reader monad carrying an allocator and an IO interface โ the same shape Haskell's IO and IO# have. He frames monads not as "obscure math-y thing" but as the algebraic description of imperative programming as a computational context: you implement MonadCont to get imperative semantics, LogicT for nondeterminism with backtracking. The point is that not having a built-in notion of time gives the language more expressive ceiling and a higher optimization ceiling. Zig's team apparently arrived at the IO-passing pattern independently, which the author reads as confirmation that the pattern is universal.
(I don't fully buy the framing โ passing an explicit io parameter is just dependency injection, and calling that "the IO monad" is a stretch unless you also have do-notation and a way to compose โ but the underlying observation, that explicit effect-carrying is what both designs are doing, seems right.)
Bottom line
The author's score:
- Expressiveness: comparable to Haskell, less noise than C++ or Rust for his use cases.
- Type-system programming: comptime is "at least in the ballpark of Haskell and easier to program at."
- Mean-free path: longer than Rust, much longer than C++. He hasn't been surprised by Zig semantics so far.
He's been a Haskell user for 10โ13 years and is now redirecting energy to Zig.