The Easiest Way to Build a Type Checker

Easy Type Checker sparks a nerd feud: “simple” vs “the proper way”

TLDR: A friendly “easy mode” type checker shows how mixing guessed and stated types can work. The comments explode into a debate over whether it’s the same as the academic classic, with confusion over multi-arg functions and frustration at math-heavy explanations—making type systems feel accessible matters.

An approachable guide to building a type checker dropped, promising an “easy mode” using bidirectional type checking—basically, your code sometimes tells the computer its type, and other times the computer guesses it. The community reaction? Instant drama. One camp is cheering, posting annotated snippets like a play-by-play of the famous rules. Another camp is squinting: is this the same as that classic academic method everyone hears about? Cue the confusion and spicy replies.

The biggest flare-up: folks arguing whether this resembles the old-school, fully automatic method taught in academia. Some readers, like tayo42, are convinced it’s the same thing—then immediately second-guess it. Others, like thomasikzelf, say academic explanations are gatekeeping-by-notation, making it harder than it needs to be. Meanwhile, nkrisc asks the question everyone’s secretly thinking: how do you even represent a function that takes multiple inputs without your brain melting?

For comic relief, a few commenters joked that Algorithm W (the classic method) stands for “Why is this so hard?” and compared the examples to matryoshka functions—functions inside functions inside functions. And yes, someone dropped their own mini type checker for Python, because this crowd always has receipts: babytypechecker. TL;DR: fun code, big opinions, and a gentle roast of math-heavy explanations.

Key Points

  • The article presents bidirectional type checking as a practical way to implement a type checker with separate infer and check phases.
  • Unlike Hindley–Milner, this approach requires some type annotations, typically at function definitions, while allowing bodies to remain annotation-free.
  • A minimal language is defined with number, string, and function types, and expressions including literals, var lookups, functions, calls, lets, and blocks.
  • The infer function validates calls against function types, rejects inferring unannotated functions, handles let annotations with type equality checks, and maintains block scoping.
  • The check function verifies functions against expected function types by binding parameters and checking bodies, and handles blocks using scoped contexts.

Hottest takes

"I thought the implementation here was how hindley Milner worked? I guess not?" — tayo42
"It seems like HM is mostly explained by people with a mathematics background" — thomasikzelf
"I can't parse the code well enough just in my mind to tell if that would work..." — nkrisc
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.