The return function in Haskell has little to do with the return keyword in imperative programming languages—it’s just an ordinary function with an ordinary type signature:
return :: Monad m => a -> m a
Basically, return takes any old value and “lifts” it into a monad. It’s a little clearer what this function does when you replace the m with a concrete type, like Maybe:
return :: a -> Maybe a
There’s only one implementation of the above function, and that’s Just, so return = Just for the Maybe monad.
In your case, you are using the function monad, (->) r, also often called the “reader” monad. Performing the same substitution as with Maybe, we get the following signature:
return :: a -> r -> a
This function also has only one implementation, which is to ignore its second argument and return its first. This is what const does, so return = const for functions.
The question of “when to use return” is a reasonable one, but it should make more sense after understanding the above: you need to use return when the value returned from a function passed to >>= is not monadic, so it needs to be “lifted”. For example, the following would be a type error:
Just 3 >>= \x -> x + 1
Specifically, the right hand side needs to return a Maybe Int, but it only returns an Int. Therefore, we can use return to produce a value of the correct type:
Just 3 >>= \x -> return (x + 1)
However, consider a similar expression. In the following case, using return would be a type error:
Just [("a", 1), ("b", 2)] >>= \l -> lookup "c"
That’s because the result of the lookup function is already a Maybe Int value, so using return would produce a Maybe (Maybe Int), which would be wrong.
Returning to your example using the function monad, (n+) is already a function of type Int -> Int, so using return would be incorrect (it would produce a function of type Int -> Int -> Int). However, d + d is just a value of type Int, so you need return to lift the value into the monad.
It’s worth noting that, in both cases, you could always replace return with its underlying implementation. You could use Just instead of return when using the Maybe monad, and you could use const instead of return when using the function monad. However, there are two good reasons to use return:
Using return lets you write functions that work with more than one kind of monad. That is, return gets you polymorphism.
It’s extremely idiomatic to use return to lift plain values into a monadic type, so it’s clearer and less noisy to always see return instead of seeing many different functions with different names.