This is a nice approach. Thanks to all of you in this thread. I think I'll try something like this when I introduce Haskell I/O in my Programming Languages class in a month or two.
If this is meant to be under main, you need a "let":
main = do
let greet name = putStrLn ("Hello, " ++ name)
getLine >>= greet
For whatever reason, I didn't learn about the magic let syntax in do-notation until relatively late. Anyways this is very elegant, but not something I could have generated early on, especially because it mixes two different sequencing syntaxes (do-notation and >>=).