[HN Gopher] Monads are too powerful: The expressiveness spectrum
       ___________________________________________________________________
        
       Monads are too powerful: The expressiveness spectrum
        
       Author : hackandthink
       Score  : 39 points
       Date   : 2025-10-12 05:11 UTC (3 days ago)
        
 (HTM) web link (chrispenner.ca)
 (TXT) w3m dump (chrispenner.ca)
        
       | PaulHoule wrote:
       | I'd argue the exact opposite. Compared to what you can do if you
       | can _write compilers_ anything that involves _composing
       | functions_ is weak beer and most monad examples cover
       | computational pipelines as opposed to computational graphs. It 's
       | like that Graham book _On Lisp_ , it's a really fun book but then
       | you realize that screwing around with functions and macros
       | doesn't hold a candle to what you learn from the Dragon Book.
        
         | taeric wrote:
         | I maintain that the big advantage of the On Lisp approach is
         | that all of that is available without having to write a new
         | compiler.
         | 
         | Granted, I also don't have as heavy an attachment to pure
         | functional as most people seem to build. Don't get me wrong,
         | wanton nonsense is nonsensical. But that is just as true in
         | immutable contexts.
        
           | PaulHoule wrote:
           | What I found remarkable about that book is that 80% of what
           | is in it can be done with functions and no macros, mostly you
           | can rewrite the examples in Python except for the coroutines
           | but Python already has coroutines. It also irks me that the I
           | don't think the explanation of coroutines in Scheme is very
           | clear but it's become the dominant one you find in the net
           | and I can't find a better one.
           | 
           | As for 'compiler' you also don't need to go all the way to
           | bare metal, some runtime like WASM or the JVM which is more
           | civilized is a good target these days.
        
             | taeric wrote:
             | Totally fair. I think a lot of the things we used to do in
             | the name of efficiency has been completely lost in the
             | progress of time. Largely from the emergence and refinement
             | of JIT compilers, I think?
             | 
             | That is, a lot of why you would go with macros in the past
             | was to avoid the expense of function calls. Right? We have
             | so far left the world of caring about function call
             | overhead for most projects, that it is hard to really
             | comprehend.
             | 
             | Coroutines still strike me as a hard one to really grok. I
             | remember reading them in Knuth's work and originally
             | thinking it was a fancy way of saying what we came to call
             | functions and methods. I think without defining threads
             | first, defining a coroutine is really hard to nail down.
             | And too many of us take understanding of threads as a
             | given. Despite many of us (myself not immune) having a bad
             | understanding of threads.
        
               | bvrmn wrote:
               | Coroutines as a technique to implement state machines is
               | the first things which comes to my mind. It's a more
               | abstract and requires a way less fundamentals to know
               | comparing to concurrency.
        
               | taeric wrote:
               | But coroutines really only work any better than "objects"
               | if you understand the implication to the stack pointer?
               | Which requires understanding exactly what a thread is.
               | Right?
               | 
               | That is, a basic class that has defined state and methods
               | to modify the state is already enough to explain a state
               | machine. What makes coroutines better for it?
        
             | andersmurphy wrote:
             | Yeah, I've had fun using macros to create optimised
             | functions at runtime (inline caching effectively) and/or
             | generate code that is more friendly to the JVM JIT.
             | 
             | Also, there's always plenty of use for doing work at
             | compile time.
             | 
             | In some sense they can also be seen as a better code
             | generation.
        
         | instig007 wrote:
         | > if you can write compilers anything that involves composing
         | functions is weak beer
         | 
         | > screwing around with functions and macros doesn't hold a
         | candle to what you learn from the Dragon Book.
         | 
         | ---
         | 
         | So, what is it that you learn from that book that's a
         | revelation for you compared to the weak beer of composable
         | effect systems?
        
         | fn-mote wrote:
         | > screwing around with functions and macros doesn't hold a
         | candle to what you learn from the Dragon Book
         | 
         | This depends a lot on what you mean. My first take is that the
         | more you know about macros the more you realize what they can
         | do.
         | 
         | I don't know what your takeaway from the Dragon Book was, but
         | writing DSLs using macros feels very usefully powerful to me.
         | 
         | I think you are undervaluing modern macros.
        
         | veqq wrote:
         | But lisp programs are compilers. That's the whole point of lisp
         | and macros. Your functions can happily emit assembly direction.
        
       | whycombinetor wrote:
       | Yes. For the same reason that the Yoneda lemma and the Cayley
       | theorem are almost meaningless tautologies once you fully
       | understand what they're saying. "Every small thing (of a certain
       | type) is able to be expressed as a subcase of a bigger thing that
       | contains every single possible subcase in existence." Well no
       | shit.
        
       | IshKebab wrote:
       | Interesting, but it seems like he kind of proved himself wrong?
       | Monads are the only option he presented that _are_ sufficiently
       | powerful for normal programs.
        
         | bokumo wrote:
         | I don't think you're being fair to Chris Penner. He ends his
         | blog post with: "It may take me another 5 years to finally
         | finish it, but at some point we'll continue this journey and
         | explore how we _can_ sequence effects using the hierarchy of
         | Category classes instead. " Emphasis by me.
         | 
         | So while it is true, that what he has described so far is not
         | sufficiently powerful for normal programs, he has clearly
         | stated that there are more abstractions between Applicative and
         | Monad to explore than what he has presented so far.
        
       | bionhoward wrote:
       | And here I thought it was a pedantic word for "data box"
        
       | jcmontx wrote:
       | Haskell looks a heck lot like F#, even more than Ocaml if you ask
       | me
        
         | gowld wrote:
         | Paging John Harrop...
         | 
         | https://news.ycombinator.com/item?id=1396763
        
       | SchemaLoad wrote:
       | I tried learning Haskell for a decent chunk of time and could
       | make some stuff, but despite trying to learn, I still could not
       | tell you what a monad actually is. All the explanations for it
       | seemed to make no sense.
        
         | gowld wrote:
         | The important thing to know first is that a monad is not a
         | single thing like "Optional". "monad" is a pattern or
         | "interface" (called a "typeclass" in Haskell), that has many
         | implementations, (Optional, Either, List, State Transormer, IO
         | (Input/Output), Logger, Continuation, etc). Sort of how
         | "Visitor" pattern in C++/Java is not a single thing.
         | 
         | https://hackage.haskell.org/package/base-4.21.0.0/docs/Contr...
         | 
         | https://book.realworldhaskell.org/read/monads.html
         | 
         | A common metaphor for monad is "executable semicolons". They
         | are effectively a way to add (structured) hook computations
         | (that always returns a specific type of value) to run every
         | time a "main" computation (akin to a "statement" in other
         | languages) occurs "in" the monad.
         | 
         | It's sort of like a decorator in Python, but more structured.
         | It lets you write a series of simple computational steps
         | (transforming values), and then "dress them up" / "clean them
         | up" by adding a specific computation to run after each step.
        
           | Ryder123 wrote:
           | This makes SchemaLoad's comment perfectly clear.
           | 
           | (but do I appreciate the effort you put into your reply -
           | reading that monad's are more like interfaces is new
           | information to me, and might help down the road)
        
         | hinkley wrote:
         | Unfortunately no one can tell you what a monad is. You have to
         | experience it for yourself. - Haskell Morpheus
        
         | bananaflag wrote:
         | You should first understand what a typeclass and a Functor is.
        
         | b0sk wrote:
         | This is great imo --
         | https://www.adit.io/posts/2013-04-17-functors,_applicatives,...
        
         | oncallthrow wrote:
         | A monad is just a monoid in the category of endofunctors
        
         | valiant55 wrote:
         | Forget all the academic definitions, at it's core a monad is a
         | container or wrapper that adds additional functionality to a
         | type.
        
         | bitwize wrote:
         | Just think of it as a design pattern, but a bit more strict
         | than the Gang of Four patterns. Fundamentally it's a
         | relationship between types and other types such that certain
         | operations make sense and follow well-understood rules (the
         | monadic laws). Study the monadic laws, and try playing with the
         | State, IO, and List monads to get a better sense of what those
         | operations are and why they're useful for sequencing in a pure-
         | functional context.
        
         | munk-a wrote:
         | Someone may correct me but - in three levels of conciseness...
         | 
         | A monad is a function that can be combined with other
         | functions.
         | 
         | It's a closure (or functor to the cool kids) that can be bound
         | and arranged into a more complex composite closure without a
         | specification of any actual value to operate on.
         | 
         | It's a lazy operation declaration that can operate over a class
         | of types rather than a specific type (though a type is a class
         | of types with just a single type so this is more a note on
         | potential rather than necessary utility) that can be composed
         | and manipulated in languages like Haskell to easily create
         | large declarative blocks of code that are very easy to
         | understand and lend themselves easily to abstract proofs about
         | execution.
         | 
         | You've probably used them or a pattern like them in your code
         | without realizing it.
        
         | ilikebits wrote:
         | Monads are a generalization of Promises. Each type in Monad
         | defines their own `.then` in a different way. For promises,
         | `.then` is defined as "run this function once you have this
         | deferred value from the last promise". For optionals (`Maybe`),
         | `.then` is defined as "run this function if the last optional
         | had an actual value". For Either, `.then` is defined as "run
         | this function if the last Either returned Right, otherwise
         | early-return with the value from Left" (this is functional
         | early-return, basically).
        
         | astrange wrote:
         | It's an implementation of the typeclass Monad, which happens to
         | come with a special "do" keyword.
        
         | the__alchemist wrote:
         | Nan-in received a university professor who came to inquire
         | about Monads
         | 
         | Nan-in served tea. He poured his visitor's cup full, and then
         | kept on pouring.
         | 
         | The professor watched the overflow until he no longer could
         | restrain himself. "It is overfull. No more will go in!"
         | 
         | "Like this cup," Nan-in said, "you are full of your own
         | opinions and speculations. How can I show you a Monad unless
         | you first empty your cup?"
        
       | jancsika wrote:
       | It'd be nice to have a process like the following:
       | 
       | 1. I free solo a bunch of junk in vanilla javascript with state
       | flowing hither and thither until I'm out of coffee
       | 
       | 2. I test the _exact_ behaviors(s) I wanted to make possible in
       | the GUI I just wrote.
       | 
       | 3. The framework whitelists only the event chains from my test.
       | 
       | 4. For any blacklisted event chains, the user gets a Youtube
       | video screencast of the whitelisted test so they can learn the
       | correct usage of my GUI.
        
       | spewffs wrote:
       | Yes monads in general are too expressive but the answer isn't to
       | limit the typeclass to something between applicative and monad
       | but rather to limit what monads are allowed. The problem is that
       | there should only be one monad: an effect monad loaded with
       | various effects depending on the side effect needed. Instead of
       | defining this or that monad, there should only be the capability
       | to define the effect you need.
       | 
       | In that case, everything runs within the effect monad and then no
       | one would ever really need to learn what a monad is, just that
       | some calls are effectful (like reading a file or throwing an
       | exception).
        
       ___________________________________________________________________
       (page generated 2025-10-15 23:00 UTC)