On my journing towards grasping lazy IO in Haskell I tried the following:
main = do
  chars <- getContents
  consume chars
consume :: [Char] -> IO ()
consume [] = return ()
consume ('x':_) = consume []
consume (c : rest) = do
  putChar c
  consume rest
which just echos all characters typed in stdin until I hit 'x'.
So, I naively thought it should be possible to reimplement getContents using getChar doing something along the following lines:
myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  -- And now?
  return (c: ???) 
Turns out it's not so simple since the ??? would require a function of type IO [Char] -> [Char] which would - I think - break the whole idea of the IO monad. 
Checking the implementation of getContents (or rather hGetContents) reveals a whole sausage factory of dirty IO stuff. Is my assumption correct that  myGetContents cannot be implemented without using dirty, ie monad-breaking, code?
You need a new primitive unsafeInterleaveIO :: IO a -> IO a that delays the execution of its argument action until the result of that action would be evaluated. Then
myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  rest <- unsafeInterleaveIO myGetContents
  return (c : rest)
                        You should really avoid using anything in System.IO.Unsafe if at all possible. They tend to kill referential transparency and are not common functions used in Haskell unless absolutely necessary.
If you change your type signature a little I suspect you can get a more idiomatic approach to your problem.
consume :: Char -> Bool
consume 'x' = False
consume _   = True
main :: IO ()
main = loop
  where
    loop = do
      c <- getChar
      if consume c
      then do
        putChar c
        loop
      else return ()
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With