I haven't seen anybody explain the real reasons you can't yank `a` out of something of type `IO a`, so I thought I'd attempt to clear a few things up.
It's true that you cannot *in general* extract a value of type `a` from something of type `Monad m => m a` but those reasons are *not* why you can't in the case of IO. You can't with Monad in general because the typeclass doesn't provide a method with the type `m a -> a`, in fact, it only provides the opposite: `a -> m a`.
The real reason you can't pattern match on or otherwise extract values from IO is that it's an abstract datatype - on purpose. The constructor is not exported, the internals are hidden.
You are using a non-strict programming language. The IO datatype is how the implementation knows not to replace the thunk with its value when evaluated.
Want to see what I mean?
If you aren't comfortable with monads, no amount of thrashing is going to let you avoid using Functor/Applicative/Monad if you want to interact with values produced in IO.
There are people used to teaching and assisting with the courses recommended in my guide (cis194 & NICTA course) on Freenode IRC at #haskell-beginners. There are tons of people equipped to help you in #haskell as well.
--- Chris Allen