This is basically just my attempt to explain and rewrite some Haskell code I've found on StackOverflow. It turned out to be surprisingly deep! Here's the code (collated from https://stackoverflow.com/a/20644753):
So by using the List Monad, we explore all its possible values. But what exactly is "guard"?
It turns out, we're not just using a Monad here. In Haskell, we're actually using the fact that list is a MonadPlus: roughly, a Monad plus another type class called an Alternative. This type class makes sure that our data type has an "Empty" value.
The Alternative lets us define
guard True as identity, and
guard False as "Empty". This means that when we transform the do-notation into "bind" calls, and reach the guard clause, we continue with our "Empty" value if the guard clause didn't match.
What that means for lists is that when collating the final lists at the end, the branches where the guard clauses were false will be empty. Because of the "flattening" effect of bind with lists, those branches effectively don't appear in the end result.
So in our example, the branches where we tossed "Tails" don't matter – we're able to strip them out with a guard clause.
This is "Nondeterminism", in the sense that all possible branches of the code are followed. It's up to us, later on, to choose to analyse the outcome by e.g. picking a random branch.
And of course, here's the same code in my (somewhat clunkier) Python do-notation: