There is no way to get a value of type a out of an expression of type IO a and there shouldn't be. This is actually a large part of why monads are used to model IO.
An expression of type IO a can be thought of as representing an action that can interact with the real world and, if executed, would result in something of type a. For example, the function getLine :: IO String from the prelude doesn't mean that underneath getLine there is some specific string that I can extract - it means that getLine represents the action of getting a line from standard input.
Not surprisingly, main :: IO () since a Haskell program does represent a computation/action that interacts with the real world.
The things you can do to expressions of type IO a because IO is a monad:
Sequence two actions using (>>) to produce a new action that executes the first action, discards whatever value it produced, and then executes the second action.
-- print the lines "Hello" then "World" to stdout
putStrLn "Hello" >> putStrLn "World"
Sometimes you don't want to discard the value that was produced in the first action - you'd actually like it to be fed into a second action. For that, we have >>=. For IO, it has type (>>=) :: IO a -> (a -> IO b) -> IO b.
-- get a line from stdin and print it back out
getLine >>= putStrLn
Take a normal value and convert it into an action which just immediately returns the value you gave it. This function is less obviously useful until you start using do notation.
-- make an action that just returns 5
return 5
More from the Haskell Wiki on the IO monad here.