1. A -> B betyder en funktion som tar in ett argument av typen A, och returnerar ett svar av typ B. A -> IO B samma sak, förutom att svaret är av typen IO B istället för B Dvs A -> IO B returnerar någonting av typen B wrappat i ett IO. Och det finns inget (vettigt) sätt för dig att hämta ut Bet annat än att köra hela programmet.
2. I funktionen som returnerar IO B kan du göra IO, tex läsa/skriva till filer, hämta input från användaren mm. Men som straff så kommer din funktion så fort du vill göra någon IO att fastna i "IO-monaden", dvs alla funktioner som använder den funktionen måste även dom returnerna IO nånting.
3. Det är ett sätt att hålla Haskell rent från sidoeffekter. Om du anropar en funktion som inte slutar med IO så kan du vara säker på att dess resultat alltid kommer vara detsamma för samma input.
Dvs om du i tex Java kodar en funktion som räknar ihop två tal kan du inte se på den utifrån om den alltid kommer ge tillbaka samma tal om du skickar in samma parametrar.
int Sum(int x, int y) {...}
Men om du i Haskell skriver samma funktion
sum :: Int -> Int -> Int
kan du vara säker på att skickar du in 123 och 432 kommer svaret alltid bli exakt samma. Det kan du inte i Java om du inte verkligen tittar på hur sum-funktionen är skriven.
Ett litet tips: "A Gentle Introduction to Haskell" som bjornie länkade till är inte alls speciellt gentle, så om du inte har någon egen bok att titta i kanske du hellre vill läsa tex Real World Haskell (http://book.realworldhaskell.org/read). Det finns en hög med Monad-tutorials på haskell-wikin oxå ifall du tyckte mitt inlägg sa något vettigt och det som fanns i A Gentle.. inte gjorde att du förstog allt (IO är alltså en speciell sorts "Monad"). http://www.haskell.org/haskellwiki/Tutorials#Using_monads
En funktion som är A -> IO B måste ge tillbaka svaret i ett IO. Men du kan injicera ett "vanligt" värde i IO om du vill:
test :: Int -> IO Int
test x = return (x+1)