| Even in languages where the concepts can be encoded, it can be hard to determine what aspects of a given library are the encoding and which parts are the fundamental ideas if you haven't seen the ideas used in well-suited language. For instance, I didn't really understand the use of functools.reduce[0] or itertools.starmap[1] in Python until I was familiar with zipWith[2] and foldl [3] in Haskell. The ideas themselves are not particularly complicated, but I hadn't previously worked with abstractions where the default was to operate on whole data structures rather than on individual elements, so I didn't see how you would set up your program to make those functions useful. In addition, for abstract higher-order functions, type signatures help a lot for understanding how the function operates. I found `functools.reduce(function, iterable, initializer)` significantly more opaque than `foldl :: (b -> a -> b) -> b -> [a] -> b` because the type signature makes it clear what sort of functions are suitable for use as the first argument. It's now easy for me to use the same abstractions in any language that provides it because I only have to learn the particular encoding of this very general idea. While I couldn't figure out why functools.reduce was useful or desirable, I couldn't figure out many parts of C++'s standard template library at all. But if you already know the core concepts and the general way that C++ uses iterators and the fact that functools.reduce, Data.Foldable.foldl, and std::accumulate[4] are all basically doing the same thing for the same reasons is a lot more readily apparent. [0] https://docs.python.org/3/library/functools.html#functools.r... [1] https://docs.python.org/3/library/itertools.html#itertools.s... [2] https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-... [3] https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-... [4] https://en.cppreference.com/w/cpp/algorithm/accumulate |
That's a good point. Using a proper functional programming language doesn't just enable FP ideas (you can't fake a feature like implicit capture of variables), it may also clarify them by reducing baggage.
> I found `functools.reduce(function, iterable, initializer)` significantly more opaque than `foldl :: (b -> a -> b) -> b -> [a] -> b` because the type signature makes it clear what sort of functions are suitable for use as the first argument.
I suspect you're just a better Haskell programmer than me (I've only ever dabbled), but I find the big-mess-of-arrows syntax to be pretty confusing compared to a simple tuple of descriptively named identifiers.
Perhaps related to this: I don't see the practical appeal of currying. Even C++ supports the 'bind' pattern just fine - http://www.cplusplus.com/reference/functional/bind/#example