Live data from Hacker News

Functional programming and reliability: ADTs, safety, critical infrastructure

blog.rastrian.dev

51–60 of 191 posts

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#51

It's acceptable to state, without evidence, that functional programming and static typing make things more reliable. But this isn't a falsifiable claim. We cannot possibly know if this is true or not. - Not all of banking and telecom use functional programming or even static typing. - Functional programming often leads to write-only incomprehensible code; the exact opposite of what you need to have a reliable system.…

Wait. This doesn’t make sense to me. Statically typed programming languages cannot be deployed nor can they run with a type error that happens at runtime. Untyped languages CAN run and error out with a type error AT runtime. The inevitable consequence of that truth is this:

In the spectrum of runtime errors statically typed languages mathematically and logically HAVE less errors. That by itself is the definition of more reliable. This isn’t even a scientific thing related to falsifiability. This comes from pure mathematical logic. In science nothing can be proven, things can only be falsified. But in math and logic things can be proven and it is provable that static types are more reliable than untyped.

It is definitely not vibes and feels. Not all of banking uses statically typed languages but they are as a result living with a less reliable system then the alternative and that is a logical invariant.

There are many reasons why someone would choose untyped over typed but reliability is not a reason why they would do this unless they are ignorant.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#52
post #16

I think there is a strong case that ADTs (algebraic data types) aren't so great after all. Specifically, the "tagged" unions of ADT languages like Haskell are arguably pretty clearly inferior to the "untagged" unions of TypeScript or Scala 3. Because the latter actually behave like a logical "or" rather than an artificial construct that needs to be wrapped and unwrapped.

I at first thought it was nice to save the wrapping, but you save yourself sooo much pain, ugliness and mistakes pattern matching trying to distinguish the types once you just use tagged unions.

I think you’re both pointing at the same tradeoff: “untagged” unions feel lighter, but you often pay it back in ad-hoc narrowing (shape checks/heuristics) and ambiguity once variants overlap.

Tagged unions/ADTs make the discriminant explicit, which is exactly why they tend to be reliability-friendly: exhaustive matches + explicit constructors reduce “guessing” and refactor breakage.

That said, I agree the ergonomics matter, TS-style discriminated unions are basically “tagged” too once you add a kind field, for example.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#53
post #2

This article seems to conflate strong type systems with functional programming, except in point 8. It makes sense why- OCaml and Haskell are functional and were early proponents of these type systems. But, languages like Racket don’t have these type systems and the article doesn’t do anything to explain why they are _also_ better for reliability.

You don't need a strong type system or even really ANY compile-time type system for this strategy to work! I use all these techniques in plain JS and I can still get the benefits of correct-by-construction code style just by freezing objects and failing fast.

You're about a decade too late with that argument. The best argument for dynamic types systems, is enjoying debugging in production.

In dynamic languages, you are the type system.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#54
post #8

Earlier quoted context omitted.

Yeah, I know Rust isn’t everyone’s favorite but I’d expect at least some awareness that we’ve seen a lot of reliability improvements due to many of these ideas in a language which isn’t focused on FP. I ended up closing the tab when they had the example in TypeScript pretending the fix was result types rather than validation: that idea could be expressed as preferring that style, an argument that it makes oversights…

Rust certainly isn't a pure fp language, but the borrow checkerbl is a lot kinder when you use fp style.

Sure, my point was simply that it’s not as simple as the author assumes. This is a common failure mode in FP advocacy and it’s disappointing because it usually means that a more interesting conversation doesn’t happen because most readers disengage.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#55
post #54

Earlier quoted context omitted.

Rust certainly isn't a pure fp language, but the borrow checkerbl is a lot kinder when you use fp style.

Sure, my point was simply that it’s not as simple as the author assumes. This is a common failure mode in FP advocacy and it’s disappointing because it usually means that a more interesting conversation doesn’t happen because most readers disengage.

I get why it reads like FP evangelism, but I don’t think it’s “ignoring decades of prior art.” I’m not claiming these ideas are exclusive to FP. I’m claiming FP ecosystems systematized a bundle of practices (ADT/state machines, exhaustiveness, immutability, explicit effects) that consistently reduce a specific failure mode: invalid state transitions and refactor breakage.

Rust is actually aligned with the point: it delivers major reliability wins via making invalid states harder to represent (enums, ownership/borrowing, pattern matching). That’s not “FP-first,” but it’s very compatible with functional style and the same invariants story.

If the TS example came off as “types instead of validation,” that’s on me to phrase better, the point wasn’t “types eliminate validation,” it’s “types make the shape explicit so validation becomes harder to forget and easier to review.”

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#56

> In banking, telecom, and payments, reliability is not a nice to have. It is table stakes. Haha as someone who has worked in one of these domains using FP even - I wish the people in charge agreed with you! Reliability is a cost center and Product-oriented Builders treat it as such.

Honestly, as someone else who does a lot of data plumbing, there is so much FTP servers with excel sheets being used as the means for official clearance processes.

There are constant data bugs in the feeds provided by major exchanges, market makers, etc, and so many iffy business rules that are basically all encoded in 100+ tab excel sheets.

Maybe this article focuses on a very specific niche of banking, but most of it is tied together with FTP and excel sheets.

I think the author would be shocked just how flaky a fundamental banking protocol like SWIFT is.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#57

> In banking, telecom, and payments, reliability is not a nice to have. It is table stakes. Haha as someone who has worked in one of these domains using FP even - I wish the people in charge agreed with you! Reliability is a cost center and Product-oriented Builders treat it as such.

Honestly, as someone else who does a lot of data plumbing, there is so much FTP servers with excel sheets being used as the means for official clearance processes. There are constant data bugs in the feeds provided by major exchanges, market makers, etc, and so many iffy business rules that are basically all encoded in 100+ tab excel sheets. Maybe this article focuses on a very specific niche of banking, but most of…

I’ve worked in Brazilian banking stacks that were literally FTP + spreadsheets for years. So yes, the ecosystem is often messy and protocols can be flaky.

That’s exactly why I argue for stronger internal modeling: when the boundary is dirty, explicit state machines/ADTs + exhaustiveness + idempotency/reconciliation help ensure bad feeds don’t silently create invalid internal states.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#58

> In banking, telecom, and payments, reliability is not a nice to have. It is table stakes. Haha as someone who has worked in one of these domains using FP even - I wish the people in charge agreed with you! Reliability is a cost center and Product-oriented Builders treat it as such.

Yep, in practice a lot of orgs treat reliability as a cost center until an outage becomes a headline or a regulatory incident. I’ve seen the same tension in payments/banking: product pressure wins until the risk is visible.

Part of why I like “make invalid states unrepresentable” approaches is exactly that: it’s one of the few reliability investments that can pay back during feature work (safer refactors, fewer regressions), not only during incidents.

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#59
post #20
post #16

I think there is a strong case that ADTs (algebraic data types) aren't so great after all. Specifically, the "tagged" unions of ADT languages like Haskell are arguably pretty clearly inferior to the "untagged" unions of TypeScript or Scala 3. Because the latter actually behave like a logical "or" rather than an artificial construct that needs to be wrapped and unwrapped.

> "tagged" unions of ADT languages like Haskell are arguably pretty clearly inferior to the "untagged" unions of TypeScript dude .. wut?? Explain to me exactly how this is true, with a real world example. From where I stand, untagged unions are useful in an extremely narrow set of circumstances. Tagged unions, on the other hand, are incredibly useful in a wide variety of applications.

Example: Option types. Maybe a function returns an optional string, but then you are able to improve the guarantee such that it always returns a string. With untagged unions you can just change the return type of the function from String|Null to String. No other changes necessary. For the tagged case you would have to change all(!) the call sites, which expect an Option, to instead expect a String. Completely unnecessary for untagged unions.

A similar case applies to function parameters: In case of relaxed parameter requirements, changing a parameter from String to String|Null is trivial, but a change from String to Option would necessitate changing all the call sites.

> From where I stand, untagged unions are useful in an extremely narrow set of circumstances. Tagged unions, on the other hand, are incredibly useful in a wide variety of applications.

Any real world example?

Re: Functional programming and reliability: ADTs, safety, critical infrastructure

#60
post #59
post #20

Earlier quoted context omitted.

> "tagged" unions of ADT languages like Haskell are arguably pretty clearly inferior to the "untagged" unions of TypeScript dude .. wut?? Explain to me exactly how this is true, with a real world example. From where I stand, untagged unions are useful in an extremely narrow set of circumstances. Tagged unions, on the other hand, are incredibly useful in a wide variety of applications.

Example: Option types. Maybe a function returns an optional string, but then you are able to improve the guarantee such that it always returns a string. With untagged unions you can just change the return type of the function from String|Null to String. No other changes necessary. For the tagged case you would have to change all(!) the call sites, which expect an Option , to instead expect a String. Completely unnece…

I think your Option/String example is a real-world tradeoff, but it’s not a slam-dunk “untagged > tagged.”

For API evolution, T | null can be a pragmatic “relax/strengthen contract” knob with less mechanical churn than Option (because many call sites don’t care and just pass values through). That said, it also makes it easier to accidentally reintroduce nullability and harder to enforce handling consistently, the failure mode is “it compiles, but someone forgot the check.”

In practice, once the union has more than “nullable vs present”, people converge to discriminated unions ({ kind: "ok", ... } | { kind: "err", ... }) because the explicit tag buys exhaustiveness and avoids ambiguous narrowing. So I’d frame untagged unions as great for very narrow cases (nullability / simple widening), and tagged/discriminated unions as the reliability default for domain states.

For reliability, I’d rather pay the mechanical churn of Option during API evolution than pay the ongoing risk tax of “nullable everywhere.

My post argues for paying costs that are one-time and compiler-enforced (refactors) vs costs that are ongoing and human-enforced (remembering null checks).

Post reply on HN