Most of the monads I can think of belong in one or both of these categories:
State
Can be modelled as a state monad
Reader
Writer
State
ST
STM
function (((->) r))
Identity (state with no state)
Error
Sequencing with early exit
Maybe
Either
ErrorT
Both
IO (with the real world as state)
parser combinators
The only (useful) exception I can think of, whose functionality is clearly distinct from both these categories, is List (and Cont, which is merely a generalization of Monad itself).
Are there any other monads, that can’t be modelled exclusively by either category, that I have missed?
I see your point. By error, I mean ‘just perform regular pure (or stateful) computation, unless stopped by some exceptional condition,’ i.e. only carrying a single (optional) value. List does more than that, in that it applies computation to multiple items, so it can’t be ‘classed’ with the error monads, under my definition.
My objective is to provide a perspective on monads from a practical (maybe application) programmer’s perspective. I’m musing that maybe monads are over-abstracted, and it’s possible to define an easier-to-reason-about abstraction based on the concepts of state and early exit for practical programming.
For me personally, I don’t even find the list monad useful - i find it obfuscates more than writing the code explicitly, and doesn’t really give any helpful intuitions. I’d be curious to hear if someone has a different perspective.
I’d argue that monad transformers are really useful but also very clunky without MTL/some effect system, either of which need abstract monads. Being able to mix state+non-determinism or streaming+async+resource management seems a lot harder without abstract monads.
For extra monad types: There is a (maybe a bit underused) pattern of profunctor monads that can do bidirectional things, basically a question-answer free monad
This is useful if you need bidirectional things like parse/pretty print, query/update, etc. The refinery library uses it, but I’m pretty sure I’ve seen it in some serialization libraries as well.
There are also variants on a bunch of monads like adding codensity on top or tricks like ‘a smart view in datatypes’ which can really help performance and for which an abstract view on monads can help.