4 ms·
> And I suggested that this is overly complicated and procedural approaches are better. In procedural code we don't "assemble chained operations". We do them on
by KirinDave 8y ago
> And I suggested that this is overly complicated and procedural approaches are better. In procedural code we don't "assemble chained operations". We do them one-by-one and handle errors appropriately.
Go does this. It's widely and I think rightly criticized for this. It's "easy" to do but not "simple" because it's prone to human error.
> And we can typically arrange the data and control so that error handling is much easier. That was my point.
You can do more work to validate in a separate pass if we're discussing data transforms. It's harder to do this for a series of chained imperative steps. The talk details an example making a series of API queries. It's fantastic to handle a CRUD loop with the ADT method because it lets you write a simple specification and collect errors out in the end, while reserving exception handlers for truly exceptional cases like network faults. F# is incredibly good at this kind of flow.
> ADTs and FP techniques provide only syntactic sugar to avoid this spaghetti in the source code. But due to that they just encourage having the worst mess of control actually happen on the machine.
You've said this multiple times, but it's just not true. The F# code is just a function that calls functions. F#, ML and Haskell compilers all aggressively inline these calls. You pay the exact same costs for validating an error exists in the Golang style, in practice. Indeed, lots of people generate Go from liskov-style templates JUST to get ADTs to make error handling less painful. It's gaining popularity in Swift and Rust as well. Folks there aren't trying to impress people with their FP knowledge, they're cribbing a technique that works and scales well.
> My example does not have a single if statement (yes, you might argue there are if statements hidden in the for loops). I clearly stated that it's often possible to choose this approach.
Your example, by your own admission, doesn't address error handling flows. You need conditional logic to work with operations that don't always succeed. You say, "Structure it so you never have them." I think a lot of FP people would agree with this (in fact, there is a really cool functional pearl about doing exactly this at scale: https://github.com/matt-noonan/gdp-paper/releases/download/june-2018-draft/gdp.pdf https://github.com/matt-noonan/gdp-paper/releases/download/j...) but they'd think about it less as a function of assurances and "thinking very hard" and more about using methods to make inconsistent code provably false at compile time.
Very few languages can actually encode formal notions of correctness, right now. Recently languages like Idris, Agda, Coq, and TLA come up as tools for formal correctness, where you can actually have your compiler prove your invariants and their implications.