As someone that knows enough cat theory and fp to scoff at most formal presentations (including all of the famous hypebeast ones hn loves to recommend), I have to say bravo to that guy (person) for doing something I've thought of doing many times (and doing it very well!).
My strongly held belief is that FP/category theory is a language game (in the wittgenstein sense) played for its own sake.
If you don't know fp and you're curious/impressed by all the jargon and I told you functor/monad/applicative is all just a means to runtime operator overloading would you still be as impressed?
And if you do know fp and I say the same to you, if your response is I'm wrong, can you please give me a concrete example for something that Applicative (or one of those other things) can do that runtime operator overloading can't? And don't allude to purity or laziness because those are orthogonal. Here I'm talking about specifically what `lift` and `bind` enable you to compute. Further preempting the very common responses: equational reasoning is an artifact of the type system that enforces various "contracts". You can enforce the same contracts in whatever imperative language (at runtime, at compile time, whatever).
I think this is more in the lines of mixing up concepts (the language features that enable implementing functors etc. in Haskell with functors as used in programming). I liked the JavaScript monad example in the grandparent, even if it was underwhelming. It is similar to Douglas Crockford's presentation of monads (using JavaScript, but with more interesting examples like promises).
Type classes (as a language construct) are a way of doing ad-hoc polymorphism (read run-time operator overloading) more principled, and other language features can be used in place of them to implement an _interface_ for monads, functors, etc. One example is Scala's for expressions which boil down to a series of map, flatMap, filter and forEach calls so they work with any type that implements the subset of them you need without using type classes. If you want static typing and dynamic dispatch for stuff like monads then you'd want something like type classes or F-bounded polymorphism (what I allude to with the Mappable interface below) to have that.
So, from what I see saying "run-time operator overloading can do what monads, etc. can do" would lead to "function pointers and closures can already do dynamic dispatch, what's the point of run-time operator overloading then?". Type classes are a way to have your cake and statically type-check it too (and they aren't the only way).
Just to clarify, functors, applicatives, and monads are basically interfaces for polymorphic (generic) types with useful properties (which aren't checked by the language unless you're going out of your way to use something like Agda, so that's not the point) and they turn out to model accessing and changing data in a context in a nice way. You can just call them Mappable, Liftable, and Joinable and ship them in a Java library.
I agree the language game part of it, the idea for them comes from category theory but they are different from what category theorists had in mind, and the jargon could be toned down to emphasize what they are useful for. I think the big idea is that a list (or an option) isn't the only thing that has a meaningful map and flatMap implementation, which is much simpler than "a monad is just a monoidal object in the category of endofunctors over Haskell types, what's the problem?"
>I think this is more in the lines of mixing up concepts (the language features that enable implementing functors etc. in Haskell with functors as used in programming).
You know how you can identify an fp person? They'll condescend to you and dismiss what you say.
>Type classes (as a language construct) are a way of doing ad-hoc polymorphism (read run-time operator overloading)
You're glossing over what I'm saying and drawing some superficial analogy that I am not - I'm not talking parametric polymorphism, I'm talking about monadic evaluation ie evaluation within a context. I'm talking about the same thing as dynamic binding, which is also used to implement the same exact things as monads (see the collapsing interpreters paper by Amin and Rompf).
So no I'm not confused and I'm not conflating, I am in fact making a strong claim. Again, my proof is exactly using the same language: a morphism between runtime operator overloading and lift/bind.
To give a more abstruse argument, compare Conal Elliot's compiling to categories and jax (which is immediately recognized as a monadic interpreter framework).
I misinterpreted what you said then, sorry about that.
The examples you give were helpful to understand what you mean by "runtime operator overloading"--specifically, the Amin & Rompf paper. It's been a while since I read it but looking at it again reminded me of the similar terminology they use. I agree that having a multi-staged language gives you the benefits of using monads (as in abstracting away/carrying around context).
> You know how you can identify an fp person? They'll condescend to you and dismiss what you say.
Just to note, I don't have a strong preference towards trying to do everything with a monad, stacking them, etc. and I am definitely not an "fp person".
My strongly held belief is that FP/category theory is a language game (in the wittgenstein sense) played for its own sake.
If you don't know fp and you're curious/impressed by all the jargon and I told you functor/monad/applicative is all just a means to runtime operator overloading would you still be as impressed?
And if you do know fp and I say the same to you, if your response is I'm wrong, can you please give me a concrete example for something that Applicative (or one of those other things) can do that runtime operator overloading can't? And don't allude to purity or laziness because those are orthogonal. Here I'm talking about specifically what `lift` and `bind` enable you to compute. Further preempting the very common responses: equational reasoning is an artifact of the type system that enforces various "contracts". You can enforce the same contracts in whatever imperative language (at runtime, at compile time, whatever).