You do it the exact same way—once you're living so deeply in the IO
monad many things will feel a great deal like its imperative cousin.
import Data.IORef
counting :: ((Int -> IO ()) -> IO ()) -> IO [Int]
counting fun = do
store <- newIORef []
fun (\new -> modifyIORef store (new:))
readIORef store
Note the use of rather higher order function types to parameterize counting
over functions of the type of countToFive
. For an even more mind-bending experience it's interesting to note that this method is consistent with "continuation passing style". In a very real sense countToFive
"contains" a list of integers and simply has a tricky method of "getting it out".