Skip to content
HomeVideosBooksBlogs
AllTop postsTopics
Podcasts
HistoryListsWatch laterLiked videosFollowing

The videos, books, blogs and podcasts Hacker News keeps recommending, all in one place.

VideosBooksBlogsPodcastsAboutPrivacySettings

Data from Hacker News, HackerTube, HackerBooks, HackerBlogs and Open Library. Credits · Not affiliated with Y Combinator.

HomeVideosBooksBlogsPodcasts
Ctrl K
    A

    Alexis King

    lexi-lambda.github.io · Personal blog · on HN since 2015

    Alexis King writes about Haskell, type systems, and programming language design, and she created the Hackett language.

    Visit blogRSSHN submissions
    Languages & CompilersProgramming
    What HN says

    Commenters repeatedly point to 'Parse, Don't Validate' as classic must-read, and call her an excellent programmer and great writer.

    Stats for nerds
    172HN people shared it
    49linked in comments
    3.4Kstory points
    Feb 2026last shared
    2017people per year2026

    Top posts on HN

    1. 1
      Parse, Don’t Validate
      99 people · 1.4K points · first shared 2019 · 270 comments on HN
    2. 2
      Dynamic type systems are not inherently more open
      17 people · 386 points · first shared 2020 · 275 comments on HN
    3. 3
      Names are not type safety
      6 people · 318 points · first shared 2020 · 125 comments on HN
    4. 4
      An opinionated guide to Haskell
      6 people · 263 points · first shared 2018 · 92 comments on HN
    5. 5
      Four months with Haskell
      2 people · 249 points · first shared 2016 · 117 comments on HN
    6. 6
      Realizing Hackett, a metaprogrammable Haskell
      8 people · 161 points · first shared 2017 · 32 comments on HN
    7. 7
      Learning Haskell – A Racket programmer's foray into the land of Haskell
      1 person · 132 points · first shared 2015 · 94 comments on HN
    8. 8
      Types as axioms, or: playing god with static types
      5 people · 114 points · first shared 2020 · 25 comments on HN
    9. 9
      Defeating Racket’s separate compilation guarantee
      1 person · 109 points · first shared 2019 · 5 comments on HN
    10. 10
      Climbing the infinite ladder of abstraction
      4 people · 81 points · first shared 2016 · 24 comments on HN

    What HN people wrote when they linked it

    • anyonecancodeJul 2021

      I think copilot is solving the wrong problem. A future of programming where we're higher up the abstraction tree is absolutely something I want to see. I am taking advantage of that right now -- I'm a decently good programmer, in the sense that I can write useful, robust, reliable software, but I'm pretty high up the stack, working in languages like Java or even higher up the stack that free me from worrying about the fine details of memory allocation or the particular architecture of the hardware my code is running on.

      Copilot is NOT a shift up the abstraction tree. Over the last few years, though, I've realized the the concept of typing is. Typed programming is becoming more popular and prominent beyond just traditional "typed" languages -- see TypeScript in JS land, Sorbet in Ruby, type hinting in Python, etc. This is where I can see the future of programming being realized. An expressive type system lets you encode valid data and even valid logic so that the "building blocks" of your program are now bigger and more abstract and reliable. Declarative "parse don't validate"[1] is where we're eventually headed, IMO.

      An AI that can help us to both _create_ new, useful types, and then help us _choose_ the best type, would be super helpful. I believe that's beyond the current abilities of AI, but can imagine that in the future. And that would be amazing, as it would then truly be moving us up the abstraction tree in the same way that, for instance, garbage collection has…

    • hutaoFeb 2026

      Note that the division-by-zero example used in this article is not the best example to demonstrate "Parse, Don't Validate," because it relies on encapsulation. The principle of "Parse, Don't Validate" is best embodied by functions that transform untrusted data into some data type which is correct by construction.

      Alexis King, the author of the original "Parse, Don't Validate" article, also published a follow-up, "Names are not type safety" [0] clarifying that the "newtype" pattern (such as hiding a nonzero integer in a wrapper type) provide weaker guarantees than correctness by construction. Her original "Parse, Don't Validate" article also includes the following caveat:

      > Use abstract datatypes to make validators “look like” parsers. Sometimes, making an illegal state truly unrepresentable is just plain impractical given the tools Haskell provides, such as ensuring an integer is in a particular range. In that case, use an abstract newtype with a smart constructor to “fake” a parser from a validator.

      So, an abstract data type that protects its inner data is really a "validator" that tries to resemble a "parser" in cases where the type system itself cannot encode the invariant.

      The article's second example, the non-empty vec, is a better example, because it encodes within the type system the invariant that one element must exist. The crux of Alexis King's article is that programs should be structured so that functions return data types designed to be correct by…

    • hansvmAug 2023

      You make your life substantially easier if all the functions/methods/procedures/blocks/... in your code are "total" -- if they transform every possible input into the output one would expect from the name and type signature. With that as a guiding principle, I tend toward the following strategies, the particular choice of which depends on other details. Most often I'll combine 2/5, throwing a compile-time error for the broken branches, later realizing that the abstraction I chose was stupid, and then writing code that actually does what I want.

      1. Inline the work being done. If you've only implemented a single case it doesn't deserve a named function that does something different from what the name indicates. Refactor it later if you ever need when you have more cases.

      2. Ensure the error happens at compilation. C# has diagnostic directives. Zig has the @compileError builtin. C/C++ can fail using the preprocessor. It's a relatively common feature, and if you ensure that when your buggy/unfinished function compiles it's correct then that mitigates the harm you might cause (and serves as documentation: @compileError("TODO: ...")).

      3. Ensure the type signature captures the problem. If some inputs result in crashes, return an error-code/error-condition/failure-union/optional/nullable/... so that the caller knows shit might happen and can deal with it at runtime if it does.

      4. Make it abundantly clear that there's an issue. Name it…

    • teneJun 2022

      > no commonly used statically typed language helps here because they all allow null references

      This is false.

      TypeScript, Swift, and Rust are commonly used and support non-nullable references.

      > those languages, don't help you because you are dealing with real world data where inputs to your system can be null or not so you end up using some type system escape hatch anyway.

      You don't need escape hatches to deal with "real world data" that may be missing some values. This blog post is my favorite detailed comparison of handling "real world data" in static vs dynamic languages: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-type-systems-are-not-inherently-more-open/

      Rust's serde_json docs on "Operating on untyped JSON values" are also a pretty good description of working with "real world data" where you want to examine an arbitrary document: https://docs.serde.rs/serde_json/#operating-on-untyped-json-values

      The only requirement for working with "real world data" in a static non-nullable language is to choose whatever kind of behaviour you want when working with the data. Everything you can do with null references, you can do better with option types; there is nothing that null references uniquely permit.

    • kh9sdSep 2024

      Very nice article, I liked it a lot! It personally resonated with me and my own conclusion that the core "benefit" of FP is (for lack of a better work, stupid Bitcoin) "proof of work".

      Writing functions FP is essentially all about returning results from a function, which is proof that that a computation has occurred. If you don't have that return value, that proof, then obviously the rest of your code can't and shouldn't continue, and FP makes it obvious compared to more traditional imperative approaches.

      And this idea extends into so many other things that people consider core, or at least originating from FP. Result/Option types come to mind, making the possible failure of "proof of work" explicit in the type signature, so people are forced to consciously handle it. It also leads into the whole idea of type driven design, one of my favorite articles, "Parse, don’t validate"[1], describes this as well, making types that clearly restrict and set the expectations needed for the "proof of work" to always be returned from a function.

      [1] https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/

    • dharmaturtleOct 2022

      Zod allows for more complex validation like "input cannot exceed 256 chars", "number must be positive", or even arbitrary "refinements". I could, of course, simply write a function that will `Abort` instead, but tRPC+Zod handles that automatically - zero boilerplate. My current understanding is that I'll need to invoke Abort manually if the Zod.parse fails.

      Importantly Zod philosophically follows "parse, don't validate" https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ which means that once validation is done, you get a type - a parsed value. This means you can validate clientside and serverside using the same types. Again, sure you could do the same with Telefunc, but you still need to invoke Abort manually and every single RPC definition you have needs to be followed by Zod.parse. A small cost to be sure, but what are the advantages of Telefunc over tRPC? I'm not seeing any right now.

      tRPC also isn't strongly tied to Zod, it also works with yup, superstruct, and custom validators.

    Related

    Well-Typed Blogwell-typed.com60 people

    Falsify: Hypothesis-Inspired Shrinking for Haskell (2023)

    Well-Typed Blog
    Company · last shared 2026
    Matt Parsonsparsonsmatt.org57 people

    Write Junior Code

    Matt Parsons
    Personal · last shared 2026
    Simon Marlowsimonmar.github.io30 people

    Haskell in the Datacentre

    Simon Marlow
    Personal · last shared 2026
    LiquidHaskell Blogucsd-progsys.github.io42 people

    Dependent Types now almost batteries-included in GHC Haskell

    LiquidHaskell Blog
    Company · last shared 2026
    Patrick Thomsonblog.sumtypeofway.com15 people

    An Introduction to Recursion Schemes (2014)

    Patrick Thomson
    Personal · last shared 2024
    Monday Morning Haskellmmhaskell.com26 people

    Real World Haskell

    Monday Morning Haskell
    Company · last shared 2025
    Apfelmusapfelmus.nfshost.com22 people

    How Does Lazy Evaluation Work in Haskell? (2014)

    Apfelmus
    Personal · last shared 2023
    Hillel Waynehillelwayne.com294 people

    1/0 = 0

    Hillel Wayne
    Personal · last shared 2026