3 ms·
I love functional programming and I think every CS major should learn the key concepts of it: higher-order functions, immutability, purity, and how they can lea
by jasperry 5y ago
I love functional programming and I think every CS major should learn the key concepts of it: higher-order functions, immutability, purity, and how they can lead to better designs and more reliable software.
However, I believe that even after the learning curve has been scaled, the task of writing code in functional languages is objectively more difficult in at least one way: Coding a function in the expression-oriented syntax of functional languages has a higher cognitive load than coding that same computation as a sequence of statements. You simply have to hold more things in your head.
- matheusmoreira 5y ago> higher-order functions, immutability, purity These concepts aren't hard to understand and are actually incredibly useful. At some point though things get so abstract it's really difficult to understand what's going on. I've seen Haskell libraries that do things I can't explain for reasons I don't understand and the extremely detailed README with diagrams and arrows and everything somehow made it even more complex.
- Twisol 5y ago> At some point though things get so abstract it's really difficult to understand what's going on. A lot of that comes down to extremely advanced use of Haskell's type system. Advanced type systems are valuable, and they're easier to add to FP languages, but I wouldn't consider them to be a fundamentally FP concept. (We see very expressive type systems being included in imperative languages like Rust and Swift these days.) I think it's useful to keep in mind that Haskell is used a lot for research. You don't see Java used as a research sandbox in the same way, so you're not likely to run into run into these kinds of libraries in Java. (Though, as an aside, I consider anything that heavily uses reflection in Java to be nearly as inscrutable.) It's actually impressive just how many of these research-level libraries are practically useful in some way, even if the bar to understanding them is higher. I don't think it's a universal truth that libraries making advanced use of type systems must be difficult to understand. Taking the `lens` library as an example (and I think you were alluding to it, anyway), there's a fairly long-running thread of research around what a "lens" even is, and how they fit into a broader domain of "optics". The `lens` library was created based on one particular representation of lenses, and the community tried to find ways to unify the various kinds of optics in a way that made sense to them. I think the more recent understanding of "profunctor optics" might give us a more accessible route to understanding optics in general, separate from the whole hierarchy of distinct optics you can derive from it.
- AnimalMuppet 5y ago> Coding a function in the expression-oriented syntax of functional languages has a higher cognitive load than coding that same computation as a sequence of statements. You simply have to hold more things in your head. Interesting. That is exactly the opposite of the usual sales pitch for FP - that it simplifies things because you have to keep track of less.
- dnautics 5y ago> Coding a function in the expression-oriented syntax of functional languages has a higher cognitive load than coding that same computation as a sequence of statements. I don't know what fp's you've been using but the most common modern ones have basically all adopted the pipe operator, which make the representation of data transformation as a "sequence of statements" painfully obvious. "Take this data" "Transform it with this function" "Get this integer list out from that" "Multiply those integers by two" "Sum them up"
- jasperry 5y agoThanks for bringing that up. The shift to using the pipe operator has been an intriguing development in the community, and I've given some thought to what it implies about the difficulty of programming in functional syntax. The pipe operator helps if you have a clean sequence of steps and each function returns only the needed input for the next step. The code becomes just as unwieldy if an argument isn't in the right position, so you have to splice in a lambda, or you have to split cases on the result, in which case you have to do something monadic if you want to avoid deeper nesting. All of which looks like unnecessary friction when I know perfectly well in my head what the computation needs to do after each step. Also, when you have the pipe operator in your toolbox you now have a decision between two styles of coding that are basically inside-out from each other.
- dnautics 5y ago> The code becomes just as unwieldy if an argument isn't in the right position, so you have to splice in a lambda, or you have to split cases on the result I disagree. This is pretty clear even though it does exactlywhat you claim is terrible, and it is far, far clearer than the corresponding imperative code: https://twitter.com/DNAutics/status/1421465090856005633?s=19 https://twitter.com/DNAutics/status/1421465090856005633?s=19 Clarity in important when you're doing code reviews or fixing a bug, in anger.