Assuming a boolean valued function isNonNegInt, which returns True exactly when it is given a nonnegative integer, the return_or_recurse function is also easy to write.
Haskell's read function is polymorphic and has versions for converting from String to various kinds of numbers. Haskell knows which read to use this time because it knows that this read is supposed to produce an Int. Without something that clues Haskell in on the desired type there would be difficulties.
Where is the clue? It lies in the return type of return_or_recurse. That makes the return type of this particular return into IO Int and so it takes an Int argument.
For completeness here is how isNonNegInt might be defined
About the name “return”:
The name “return” makes sense in recurse_or_return because getInt will be invoked by Haskell's runtime IO system and our return is returning to that system.
For most monads however “return” is a poor word to use because what is foremost in our minds is that return is creating a new monadic object.
Try not to let names confuse you. In programming as in mathematics we must create names for new and sometimes complicated concepts. Normal language is inadequate for this and our word choices can be misleading.
The mathematician who wrote the well known children's book “Through the Looking Glass” was surely thinking of this naming difficulty when he had Humpty Dumpty justify his use of the word “glory” to a confused Alice this way: “it means just what I choose it to meanneither more nor less.”
By the way, you may as well think of the (>>=) combinator as “then with”.