When it comes to being whizz at programming, Moldbug fails the basic comprehension test:
“Even forgetting the macros, it’s pretty easy to see why you don’t need dynamic higher-order programming. For example, a very common operation on functions is to compose them – you have f(x) and g(x), you make h(x), defined as f(g(x)). In the right formal model, a compose operator is really no different from addition. And once you have first-class functions – which are not absolutely necessary, but certainly useful – it seems like a trivial extension.
But is it what you, the programmer, want to do? Actually, no. It is simply bad programming style. Its only effect is to make your program less comprehensible.
Because in a language with first-class functions but without dynamic higher-order programming, all you need to do is build a data structure which is the ordered pair (f(x) g(x)), and define h(x) as an operation on this structure. This may be slightly more cumbersome for the programmer. At least, if one line of code counts as ‘slightly more cumbersome.'”
No. That is not how function composition works.
I will now briefly try to describe why this is wrong, why it is elementarily wrong, and why Moldbug is both a n00b and a scrub.
Let’s say we have two functions, f : List a -> Int and g : Int -> Int. f takes a list and returns its length; g doubles the integer passed to it. We wish to compose both functions to make a new function, g . f = h : List a -> Int, which takes a list and returns double its length.
Suppose we try to do as Mr Yarvin proposes, and create an ordered pair (f(x), g(x)). f(x) will take a list, x, and return its length. g(x) will take an integer, x, and return x*2. We cannot pass the same x to both f and g, since no x can be both a list and an integer (not even in Python!). There is no therefore no way to construct this ordered pair.
The function h does not in any case take a pair of inputs. It takes a single input, a list, and returns a single output, an integer.
Function composition works by chaining functions together, so that the output of one becomes the input of another. If we wanted to apply a function h to the outputs of both f(x) and g(x), the “composition” operator would have a completely different signature, viz:
compose’ : (a ->
compose’ f g h x = h (f x) (g x)
Which is also, nota bene, a damn sight easier to write and use if you’re using a sensible language that handles partial application properly. And nobody, literally nobody, calls it “dynamic higher-order programming”. Not least because it’s all worked out at compile-time anyway.