6 ms·
Seems to be similar to the direction taken by John De Goes (using algebras to describe your problem domain, building programs from those algebras via free monad
by harveywi 9y ago
Seems to be similar to the direction taken by John De Goes (using algebras to describe your problem domain, building programs from those algebras via free monads/applicatives/etc., interpreting those programs using natural transformations). I think there is definitely something to this kind of thinking.
Both authors argue that modern programming languages do not have the best ergonomics for this style of programming, albeit it is at least possible to do most of it in languages such as Haskell and Scala.
1. Data Structures Are Antithetical to Functional Programming [http://degoes.net/articles/kill-data http://degoes.net/articles/kill-data]
2. A Modern Architecture for FP [http://degoes.net/articles/modern-fp http://degoes.net/articles/modern-fp]
3. Modern Functional Programming: Part 2 [http://degoes.net/articles/modern-fp-part-2 http://degoes.net/articles/modern-fp-part-2]
- roflc0ptic 9y agoAlso, he discusses some of the limitations of this approach here - https://m.youtube.com/watch?v=A-lmrvsUi2Y https://m.youtube.com/watch?v=A-lmrvsUi2Y He also calls for another language, although his asks for that language seem different.
- shalabhc 9y ago> Data Structures Are Antithetical to Functional Programming Interestingly I've heard a similar pov from the 'pure OO' (Smalltalk style) world as well. Specifically avoiding 'data structures' and embracing late binding.
- jcelerier 9y agoAnd both styles lead to equally unreadable code. If you can't take an average new graduate, put it in front of your code and have him be productive in your codebase in a few days it's no good.
- dmit 9y agoAn average new graduate wouldn't be productive in any codebase in a few days. And even if they were, that's a terribly low bar to set. Software development education sucks and most people have to learn on the job. So why not teach them ways to write more reliable and maintainable code.
- Tarean 9y agoThat is probably good advice but this style of coding (which comes down to lawless type classes without inherent utility) does make it much more difficult to read unknown code. Usually documentation isn't fleshed out in internal modules so I end up flipping between various instances and call sides just to figure out what the type class is supposed to do. This doesn't mean that there aren't valid use cases for this but please don't use it as default.
- runeks 9y ago> If you can't take an average new graduate, put it in front of your code and have him be productive in your codebase in a few days it's no good. So if a piece of code for securely transferring funds from one back account to another is not readable by a new graduate in a few days, it's no good? Should we remove safety abstractions from this code safe in order for the new graduate to be able to understand it in a week? A large part of software is safety-critical. How can you argue that safe abstractions, which reduce or eliminate faults, are not worth it if they can't be learned in a week or so? You wouldn't happen to work as an Equifax code-reviewer, would you?
- philipov 9y agoSounds like you have a bias for hiring inexperienced, cheep developers, and not providing them with any mentoring.
- shalabhc 9y ago> And both styles lead to equally unreadable code. Perhaps because the languages used aren't a good fit for these styles?
- bluetech 9y agoOn the other hand, from Linus Torvalds: > I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships. https://lwn.net/Articles/193245/ https://lwn.net/Articles/193245/
- chriswarbo 9y agoI don't think Torvalds' quote applies in this case: it's not really "killing datastructures", so much as "using abstract datastructures"; i.e. it's like programming to an interface rather than a concrete instance. In fact, that's exactly what it is, since he's using typeclasses (which can be thought of as a sort of interface). We could achieve a similar thing with existential types (AKA modules). I understood the Torvalds quote as being more like: would it be worse if some chunk of your library code disappeared, or if some chunk of your datastructures disappeared? If it's the former, then your library functions are "too smart", i.e. they're probably doing non-obvious things to their inputs. If it's the latter, then the data is more "self-describing". Note that I use the phrase "library functions", since (first-class) functions are a perfectly good way to represent data (e.g. Church encoding and its variants).
- barrkel 9y agoFirst-class functions can perfectly represent data, but that doesn't mean they're a perfectly good way to represent data. For example, if you use Church encoding for your numbers, how do you do static analysis of bounds checking? If you implement if-statements by passing two functions to a function which calls one or the other for truth and falsity, how do you determine dead code at compile time? You just move a bunch of problems from compile time to run time, where they're harder to reason about, in most Turing-complete languages.
- shalabhc 9y ago> move a bunch of problems from compile time to run time Perhaps this is an artificial dichotomy? What we really want is verification that some properties hold. These properties should be specified in a uniform way, irrespective of the time that the check can apply. When I specify a property, why do I have to also pick the time - 'run time' or 'compile time' and why the language used to specify exactly the same property is so different in each case? I think there is some unnecessary conflation here.
- platz 9y agoThose posts by Degoes are more polemical than techniques that he actually uses in production.
- barrkel 9y agoIt depends on whether reusing your data or reusing your code is more important; and that's application specific. Reusing code means you need to shoehorn your data into as generic a container as possible, because types are what make one bit of code incompatible with some other piece of data. Reduce the number of types, and you naturally increase the reusability of code. But there's irreducible complexity; the structure of data doesn't go away, if it's not explicit in types, it'll be implicit in code. There's a risk of it being so implicit that it's not until runtime that a description of the data being manipulated is known - this is a logical consequence of building your program by composing functions. It might be that you need to do lots of computation, and you need to heavily optimize your computation primitives. Reusing this code, and the right code, is very important. So the data needs to change shape. This is what you get in databases - the constraints of the relational model - and in monadic code dealing with lists, etc. On the other hand, programs are usually easier to understand when the data structures are mapped out explicitly, and the operations programs perform are understood in terms of projections between types or deltas within data structures. Sometimes, when projecting between types, all you need to know about a function are its input and output types, and you know what it does. Most line of business applications don't have much reused code, outside of libraries for UI and accessing external services. Data is more important. And that's fine.