|
In a typical imperative programming language, there's an "environment" that the actual lines of your program operate within. You can think of the environment as all of the sources your program can consume data from (files, databases, system clock, random number generator, keyboard, etc) and all of the sinks your program can write data into (files, databases, logs, the screen, etc). Monads are an approach to modeling the idea of running a set of statements in a particular environment, with specific input and/or output capabilities, often called "effects". In your typical programming language, you've only got one type of monad, which is the language runtime. You can do literally any type of effect at any time. That is very powerful, but it also makes programs difficult to reason about. In many typed functional programming languages, monads are used to create much more specific contexts for running sequences of computations and effects. That makes reasoning about local sections of your program way easier. One might think "why would I want to limit my power?" And the answer is you're only limiting yourself locally. It's exactly the same as how procedural programming dispensed with the all powerful GOTO, but it turned out that breaking programs into functions made them much easier to reason about. And it turns out that once you start thinking that way, you can often offload some pretty tricky logic into a well designed monad. A major caveat is that things can get pretty complex when you try to compose monads, and for me, that's where the love affair ended. There are alternative models for how to constrain effects, like algebraic effect systems, which try to be more intuitive and composable. |
The problem with many monad explanations is they only explain particular monads but then other monads become even more confusing.