Live data from Hacker News

Monads as a Programming Pattern

samgrayson.me

71–80 of 84 posts

Re: Monads as a Programming Pattern

#71
post #44

Earlier quoted context omitted.

The person you're replying to is talking about handling mutable state in a "stateless" way. That's a big distinction.

The person you're replying to is talking about handling mutable state in a "stateless" way. That's a big distinction. How so? Why is it such a big distinction? Why isn't that just encapsulation? "Handling mutable state in a 'stateless' way" is basically just Smalltalk style Object Oriented programming. (As opposed to Java or C++, which has some differences.)

The value of monads is that they fold side-effects into the return values.

  dirty languages: 

  input -> function_a -> output/input -> function_b -> output 
               ^                             ^
               |                             |
          side_effect_a                 side_effect_b
               |                             |
               v                             v
          lovecraftian_primordial_soup_of_global_state

  pure languages: 

  input -> function_a -> output/input -> function_b -> output 
               ^                             ^
               |                             |
          side_effect_a                 side_effect_b ------>
               |
               +-------------------------------------------->
If C++ were pure, the type-signatures would look like

  (output, side_effect_a) function_a(input);

  (output, side_effect_b) function_b(input);
The drawback is that the type-signature of function_b(function_a()) becomes complex. Now, function_b needs to accept and pass-on the upstream side-effects. To compose function_a and function_b, we need to convert the type-signature of function_b to

  (output, side_effect_b, side_effect_a) function_b(input, side_effect_a); 
Fortunately, ">>=" converts function_b under the hood. Which allows us to write

  function_a() >>= function_b() >>= function_c >>= function_d
and pretend that each ">>=" is just a ";" without wrestling with compound inputs and compound returns.

Re: Monads as a Programming Pattern

#72

Earlier quoted context omitted.

Functors are not useful for much on their own, so they are difficult to motivate. The Haskell formulation of applicatives doesn't make much sense outside of languages where currying is idiomatic---which is most languages. In these languages you tend to see the product / semigroupal formulation, and here applicatives become a bit trickier to explain as you need more machinery.

Functors enable the Fix functor and, from there, the whole universe of recursion schemes, so I'm not sure that I agree that they're not useful on their own.

Sure but virtually nobody cares about how to finitize a recursive function when they are trying to learn a new programming paradigm. Recursion seems to work just fine in languages that don't have any of these bells and whistles.

"Hey you can implement Fix" is like saying "now you can program in green" for most readers.

Re: Monads as a Programming Pattern

#73
post #30

I think monads highlight something underappreciated about programming, which is that different people regard very different things as "intuitive". It almost seems that modalities of thinking about programming are bigger, external things than programming itself. Certainly they're barriers to learning. Like Lisp, there seems to be about 10% of the programmer population who think "ah this is obviously the clearest way t…

How do you deal with state in a language that would prefer to be stateless? Encapsulation? No one gets direct access to the state. Instead, there are methods or functions for dealing with the state indirectly, crafted to protect those outside. Answer: wrap the entire external universe and all its messy state up into an object, then pass that down a chain of functions which can return "universe, but with some bytes wr…

>How is a Monad anything different than a particular kind of object wrapper?

It _is_ a particular type of wrapper object. That's where the whole "in the category of endofunctors" comes in. An endofunctor being a functor from something to itself.

You have IEnumberable and that lets you do SelectMany to flatmap some internal nested set of objects down to IEnumerable.

The shape of what you get back doesn't change. You get back an IEnumerable of something. That has a specific contract on which you can do specific operations regardless of the object it is wrapping.

The other piece of the puzzle is that it is monoidal. A monoid is just a collection of objects + a way of combining them + a 'no-op'. This is usually worded something like "a set of objects with an associative binary operator and an identity".

The classic definition "a monad is just a monoid in the category of endofunctors" is worth picking apart piece by piece. But it's also utterly useless because you have to spend quite awhile picking it apart and then looking at concretions of every one of the individual abstractions to understand what the hell each part individually looks like and then put it back together in your mind.

That definition is classically used as a joke because it's so terse you have no hope of understanding it without a lot of study, yet at the same time it's so precise it's all the information you need!

Re: Monads as a Programming Pattern

#74

Earlier quoted context omitted.

You really don't need to introduce groups or other algebraic structures to understand monads, and if your goal is to teach monads I believe it is harmful to do this. The average programmer is much more likely to encounter monads (e.g. error handling, promises), than they are to encounter groups in an abstract context. Unnecessary maths will drive people away. Making a big deal of axioms, reasoning, and all this stuff…

Until functional people stop speak so elitist ("me" vs average programmer), people will be driven away from these concepts

Elitist functional programmers are probably just average programmers that didn't run away screaming at the first sign of math, but instead just confronted what was presented to them and took the time and effort to properly grok the material.

Re: Monads as a Programming Pattern

#75

Earlier quoted context omitted.

Functors enable the Fix functor and, from there, the whole universe of recursion schemes, so I'm not sure that I agree that they're not useful on their own.

Sure but virtually nobody cares about how to finitize a recursive function when they are trying to learn a new programming paradigm. Recursion seems to work just fine in languages that don't have any of these bells and whistles. "Hey you can implement Fix" is like saying "now you can program in green" for most readers.

Oh, certainly. My assumption was that the GP meant that functors aren't useful on their own _in general_, rather than in the particular context of someone just getting into the typed functional paradigm. And, of course, recursion does work just fine in other languages, but (and I'm saying this more for posterity than as a retort since I assume you're well aware of this point) recursion schemes offer a layer of abstraction over direct recursion that eliminates the need to manually implement various recursive operations for each of the data structures you have at hand. As with a lot of the higher-level constructs in languages like Haskell, that level of abstraction may not have any practical benefits in most domains, but it's nice to have when it does offer a benefit in a particular domain.

Re: Monads as a Programming Pattern

#76
post #36
post #24

I guess I don't get all this "monad" stuff. This article talks about 3 types of monad. An optional, a list, and a future. However an optional is really just a list constrained to size 0 or 1. And a future is often called "not truly a monad." So I question the value of explaining this abstraction in great detail over so many articles when people struggle to come up with more than 1 concrete example of it (Lists), an e…

You can go a very long way in programming without ever needing to explicitly use a monad for anything. The usual route into needing them is something like Haskell's IO: if you want as much as possible of your code to be stateless and immutable, how do you deal with IO, which inherently changes state external to the program? If you've learned from the assembly end of programming upwards, it can be very hard to see the…

You can go a very long way in programming without realising you inadvertently have been using Monad's present in the language/standard library :P

Re: Monads as a Programming Pattern

#77
post #43
post #30

I think monads highlight something underappreciated about programming, which is that different people regard very different things as "intuitive". It almost seems that modalities of thinking about programming are bigger, external things than programming itself. Certainly they're barriers to learning. Like Lisp, there seems to be about 10% of the programmer population who think "ah this is obviously the clearest way t…

John von Neumann famously said that in mathematics you don't understand things, you just get used to them. I think monads are an example of this, and all the attempts to make them intuitive before you use them are a huge waste of time. Many mathematical concepts are like this. Take compactness. At first, the definition of compactness seems a little random, but it's useful for proving things, so you keep using it, and…

Love that von Neumann quote !

I have had this experience, that I've moved much faster learning to use math tools when a friend much more advanced than me suggested that I can use a tool even if I don't know how it works. It's like if I stopped building a house because I want to see if I can build a hammer myself !

(Well, this is also my experience programming, implementing the low level stuff myself is a much more attractive exercise than actually assembling off-the-shelf parts into something people would actually use!)

Re: Monads as a Programming Pattern

#78
post #30

I think monads highlight something underappreciated about programming, which is that different people regard very different things as "intuitive". It almost seems that modalities of thinking about programming are bigger, external things than programming itself. Certainly they're barriers to learning. Like Lisp, there seems to be about 10% of the programmer population who think "ah this is obviously the clearest way t…

How do you deal with state in a language that would prefer to be stateless? Encapsulation? No one gets direct access to the state. Instead, there are methods or functions for dealing with the state indirectly, crafted to protect those outside. Answer: wrap the entire external universe and all its messy state up into an object, then pass that down a chain of functions which can return "universe, but with some bytes wr…

What exactly do you mean by stateless? Encapsulation in the OOP sense is not stateless, because two identical method-calls may not return the same value. Example: if you have an ArrayList, calling `size` at one point in time might have a different result than calling `size` now. That's why I say the list 'remembers' its 'state'.

An object wrapper has to have the object somewhere in memory, you just can't touch it. With a monad, the object might not even exist yet (example: Promise) or there might be more than one (example: Collections).

Re: Monads as a Programming Pattern

#79

Earlier quoted context omitted.

The person you're replying to is talking about handling mutable state in a "stateless" way. That's a big distinction. How so? Why is it such a big distinction? Why isn't that just encapsulation? "Handling mutable state in a 'stateless' way" is basically just Smalltalk style Object Oriented programming. (As opposed to Java or C++, which has some differences.)

It is encapsulation with the mandatory law stating that an encapsulation of an encapsulation must be as deep as a single encapsulation. Note that this informal statement doesn't necessarily mean you have to be encapsulating data. A behavior, a contract, an assertion, compositions of all of these etc can also be encapsulated. Fun ideas (not necessarily true but fun to think about): * Monads kinda convert nesting to co…

A few observations which might also be false.

We can have arbitrarily nested monads:

  monadicObj.bind((T value) => monad.wrap(monad.wrap(value)));
Remember, `bind` only unwraps one layer. Without it unwrapping one layer, programs would continue accumulating large stacks of monads in monads.

I would also point out that it only collapses abstractions of the same kind; Maybe's bind only unwraps one layer of Maybe's. If you have a Promise> where Foo contains potentially more monads as instance-variables, those don't all get collapsed.

I like the 'converting nesting to concatenating' observation.

Sometimes we do need parentheses though, because most languages are not associative 5 - 2 - 1 is not the same as 5 - (2 - 1). Basically minus does not form a monoid, so the parens matter.

Re: Monads as a Programming Pattern

#80
post #60

Earlier quoted context omitted.

> Computing is not a subset of mathematics. And Mathematics is not a subset of Computing. Same goes with Physics (Physics is not a subset of Mathematics, despite there being way more math used in Physics than CS). if i understand you correctly, are you saying that mathematics in the classical sense is not “computing” (von neumann machines?), just as math is not physics, but math is used to model physics then the prop…

I think what I'm trying to say also goes by a well known aphorism by Alfred Korzybski: The map is not the territory [1]. We like to model stuff in computing and stuff in physics, using mathematics. What we're really doing is creating maps (math models) of the territory (computing, and physics). We notice there is some part of the stuff not fully mapped, so we make our map more complex and more elaborate. We keep maki…

This is exactly why I wanted to write this post. I feel like the pattern is valuable besides "we need it to have stateful computation." I have to mention this use for completeness, but I wanted to focus on using monads as another abstract software development pattern, because that's how it is applicable in non-FP languages (async/await for example).
Post reply on HN