1. 16

  2. 7

    I’m not sure what (if any) the point of this post is supposed to be. The most notable statement seems to be

    Monads and macros appeal to opposite urges: the urge to impose rules and the urge to get around rules.

    But no argument are made why monads would impose rules, and they indeed don’t as far as I can tell. Just because monads are most prevalent in Haskell, which does impose type checking rules, doesn’t mean the concept of monads has anything to do with it. I’m reminded of my nix-rts, which implements an IO monad in a dynamically typed language, but you can have the concept of monads in almost any language you want.

    And oppositely with macros, which I don’t think are inherently about getting around rules. Just because they’re most prevalent in Lisp, which (generally) doesn’t do any strict type checking, doesn’t mean the concept of macros has anything to do with it. I’m reminded of Rust, where the result of macros is type checked just as strictly as everything else.

    1. 3

      The argument might be more convincing if Haskell actually enforced the monad laws.

    2. 5

      Few people are excited about both monads and macros; only one person that I know comes to mind.

      Plenty of Haskell projects use both Template Haskell (macros) and monads; probably every single large-scale Haskell program includes both. Not only is there nothing wrong with mixing the two, amusingly enough Template Haskell runs in a monad! So.. not only are both useful at the same time in Haskell, you don’t get macros without monads. At the same time some of the most popular Haskell libraries use macros like lens (Control.Lens.TH) and aeson (Data.Aeson.TH). I end up using these in every Haskell program I ever write.

      Aside from that, the two concepts aren’t related at all in any way mathematically. They definitely aren’t both about information hiding.

      The author sadly gets both monads and macros totally wrong.

      Monads let you concentrate on functions by providing a sort of side channel for information associated with those functions

      Maybe is a monad. It sequences computations that can fail. There is no side channel of information at all there; a computation either fails or doesn’t. Not to mention the Sum and functions (->) which are also monads and can’t be thought of as having any side channel – they compose actions. Or Product which combines functors. This is not a good mental model for monads.

      Macros let you hide the fact that your programming language doesn’t have features that you would like

      This is at best the C view of macros “Hack stuff together because C sucks”. It’s not the view of macros that you have any language that has a proper macro system (lisp, scheme, haskell, etc.). Macros let you treat code as data, so you can do things like perform static analysis on the code, have code that generates programs, etc.

      Macros and monads are totally unrelated ideas. Macros let you modify code as if it was data. Monads sequence actions in interesting ways

      1. 3

        Monads let you concentrate on functions by providing a sort of side channel for information associated with those functions

        This is not a good mental model for monads.

        It resembles my own mental model. Monads sweep repetitive logic under the rug and let you focus on a chain of computations. Methods from particular monads—not part of the Monad interface itself—let you access or interact with that submerged logic.

        My other mental model is “statements, but made out of expressions”

        1. 1

          Beware your mental models—they may be incorrect. My own mental model for monads, that they are new types that have no constants (so they disallow optimizations like constant propagation, or that values aren’t volatile), does explain the IO, random, and sequential sequencing monads, but that’s not how they actually work (it’s an incorrect mental model).

      2. 2

        Monads provide structural support which can be reasoned about while macros extend a language. They do not seem mutually exclusive to me at all. This said with five years of hobby Haskell experience and now over a year with Janet (a lisp), also macro experience in elixir that used monad like designs to accrue state in a domain specific language.

        Composing state like monads can be done harmoniously with extending a language. My favorite macro example of this is -> which passes the output of one call to the next by rewriting the body. You’ll find similarity in how monads are evaluated. See https://clojure.org/guides/threading_macros and https://janetdocs.com/-_q%3E