Hacker News new | ask | show | jobs
by anon_d 2051 days ago
Writing functions that receive other functions as input can lead to over complicated code that's really hard to read.

I work in FP languages, and I find this type of code extremely intuitive and easy to understand.

I suspect that you are just not used to thinking this way, and that with more familiarity, you would not have this opinion.

2 comments

If I have a "known" function, map() for instance, and I pass a function into it, that's fine, because I already know what map() does. But if I have a function foo() that takes another function bar(), and I don't know what either one does, then I have to look at both foo() and bar() to understand what is going on. I have to look at two places, not just one.

But this is not unique to FP. If I'm using OOP, I can do the same thing with virtual functions. In UI frameworks I can do the same thing with callbacks.

Frankly, I don't like it, whether it's FP or not.

So you like writing functions that take 3 functions as input parameters and returns a new function that also takes a function as an input parameter and returns another function? In general excessive use of this at great depth leads to code that is not only less readable but less modular.

The complexity of higher order functions can easily be reasoned about by looking at the cardinality of the type. Sum types and product types are standard and easy to reason about.

However an exponential type that takes in an exponential type and returns another exponential type leads to cardinalities and possibilities that are much harder to reason about.

Composition of combinators is a pattern promoted by point free programming that leads not only to higher readability but greater modularity due to the reduced cardinality. Additionally cardinality of the entire type can he reduced to only analyzing the the final result of the composition.

  F = A . B . C 
The cardinality of F is all that needs to be known. The cardinality of the individual components can be ignored and you don't have to reason about this. This is not the case for higher order functions.

In general business problems that we deal with do not Require higher order functions. Higher order functions share isomorphisms with two concepts we are already familiar with: frameworks and metaprogramming.

Frameworks are programs that call your code and metaprogramming is code that writes and calls code. These things are no different then a function that takes another function in as a parameter and calls it. All three concepts are aspects of the same thing.

Therefore all the downsides of metaprogramming and all the downsides of frameworks are applicable to higher order functions.

Most of the programming problems we solve in the real world do not require metaprogramming. It can easily be avoided and solved with much more composition of combinators. Again, not saying to avoid the usage completely but the usage of higher order functions like metaprogramming should be minimal and used sparingly.

> In general business problems that we deal with do not Require higher order functions.

I cannot agree here, being currently involved in modeling and simulation work that would heavily benefit from more advanced type systems. A user would usually prefer to interact with a system with basic elements, but the interactions of the underlying domain concepts really do want to be captured with a richer set of tools.

And, to head off the "in general", there is a long tail of unique problem domains. Each individually doesn't get as much press as, say, a CRUD app, but that doesn't mean that simpler problem domains are necessarily in the majority.

I refer to business problems but in reality what I said applies to all problems.