4 ms·
Careful decisions can scale with abstractions, if they're made with some rigor. In Python, for example, whenever I'm doing operations on lists, I need to consi
by T-R 6y ago
Careful decisions can scale with abstractions, if they're made with some rigor.
In Python, for example, whenever I'm doing operations on lists, I need to consider every function in isolation - will this break for an empty list (zip), or will it break when given a generator (anything that traverses twice)? If I pass a callback with side effects, how will it behave differently if someone calls it twice?
In a a more rigorous ecosystem, I can instead only worry about edge cases on classes of functions/data types - In Haskell, when doing the same operations, I can generally assume that traversal functions were written with consideration for functor/foldable/traversable laws, and those laws tell me how I can safely compose or swap them out without breaking expectations around those edge cases. Higher Kinded Types let code be constrained to work strictly with those abstractions, so I mostly just need to worry about "does this typecheck" and, very rarely, "is this an unlawful traversal". With things like linear and dependent types entering this mix, library authors can communicate even more subtle expectations at compile time instead of leaving users to try to anticipate them or find them at runtime - when you do need to explicitly consider edge cases, the turnaround time on discovering them is important.
- munk-a 6y agoI don't disagree - these sorts of questions can be worked out to an academic degree with rigorous proofs. Databases and data guarantees around them are very widely applicable and have been isolated from business logic in modern applications due to the heavy complexity of that logic - once upon a time it was common for applications to "roll their own database" i.e. build some custom data storage approach that worked well enough (hopefully) for their purposes. I worked on a MUD based off a legacy that began in the 80s that used flat-file storage as a primary data storage method and race conditions abounded. However, databases are cost effective to build and distribute, but implementing that level of rigorous proofs for your e-commerce app is not only generally undesired but often increases the difficulty in reaching profitability and can sink a company. Working on system development isn't limited to academic concerns, if you're guiding project development you have to make really hard calls about correctness vs. cost and I say this as someone who likes to be a perfection and do things the right way whenever possible. So I don't disagree that careful decisions can scale with abstractions - it isn't the case that it is impossible to build a well designed large system, but it will be expensive and at the end of the day we all (probably?) need to balance cost of investment vs. value of that investment - or are having someone higher up the chain making that decision for us.
- chrischen 6y agoI think learning to program for correctness has a cost, but it's a skill that stays with you. Once you know how to properly model things in a composable way you can definitely work just as fast or even faster as when you gave no care for correctness. And frankly, shipping an incorrect program isn't really necessarily a worthy tradeoff as you are simply deferring problems to the user or to later down the line. And you don't need rigorous proofs to enjoy the correctness protections from strongly typed languages like Haskell. The language does that for you, you just have to learn to model in them which is a one time thing.
- agentultra 6y agoI didn't need an academic degree to start working in Haskell and learn abstractions such as "Traversal" or any of the others. Most of them are painfully simple compared to the impression one gets from their names and the jargon that comes with the territory. However the benefits of sticking with those names and jargon is that it only needs to be explained once. Analogies and metaphors help when you're starting out but you don't need to keep them around. It makes speaking precisely with colleagues in the ecosystem easier. Proofs are on another level. I've also written proofs and they require much more rigor than you will find in Haskell. It can still be done without a degree but I agree -- not useful for most line-of-business applications. However the power-to-weight ratio of learning the abstractions available in Haskell is smooth. It takes effort to acquire but it pays off in spades. That's where the "scale" comes from. Polymorphism combined with composition means that once I know a type implements "Traversal" I can use the entire language of traversals with those data types without knowing anything else about the value I'm working with. The more things that implement traversal the more rich my program becomes.
- agentultra 6y agoYou do get this idea of composition in the form of generics or template metaprogramming, not lost on me there. Type classes in Haskell, in my humble opinion, are better at consistency, keeping things coherent, and requiring less nominal boilerplate.