import Monad
import System.IO.Unsafe
import Data.IORef

infixl 0 <<

data MyIO a = MyIO (World -> (a,World))
type World = ()

instance Monad MyIO where
  return x = MyIO (\w -> (x,w))
  MyIO a >>= f
    = MyIO (\w -> case a w of
                   (r,w') -> case f r of
                              MyIO b -> b w')

myPutStrLn :: String -> MyIO ()
myPutStrLn s = MyIO (\w -> case unsafePerformIO (putStrLn s) of
                            () -> ((),w))

myGetLine :: MyIO String
myGetLine = MyIO (\w -> let s = unsafePerformIO getLine
                         in seq s (s,w))

run :: MyIO a -> a
run (MyIO act) = fst (act ())

test = run $ do
  a <- myGetLine
  b <- myGetLine
  return (b++a)

revlines = do
  l <- myGetLine
  if l == "." then return ()
   else do
    revlines
    myPutStrLn l

data YourIO a = YourIO (World -> a)

instance Monad YourIO where
  return x = YourIO (\_ -> x)
  YourIO a >>= f
    = YourIO (\w -> case f $! a w of
                      YourIO b -> b w)

yourGetLine = YourIO (\_ -> unsafePerformIO getLine)

yourPutStrLn s = YourIO (\_ -> unsafePerformIO (putStrLn s))

run2 (YourIO act) = act ()

test2 = run2 $ do
  a <- yourGetLine
  b <- yourGetLine
  return (b++a)

test3 = run2 $ do
  yourPutStrLn "hallo"
  yourPutStrLn "horst"
  return 42

err :: IO Int
err = do
  return undefined
  return 42

myErr = run $ do
  return undefined
  return 42

yourErr = run2 $ do
  return undefined
  return 42


data Tree a = Leaf a | Branch (Tree a) (Tree a)
 deriving Show

number :: Tree a -> IO (Tree (a,Int))
number t = do
  ref <- newIORef 0
  numberWithRef ref t

numberWithRef :: IORef Int -> Tree a -> IO (Tree (a,Int))
numberWithRef ref (Leaf x) = do
  n <- readIORef ref
  writeIORef ref (n+1)
  return (Leaf (x,n))

numberWithRef ref (Branch l r)
  = return Branch << numberWithRef ref l << numberWithRef ref r

(<<) :: Monad m => m (a -> b) -> m a -> m b
fAction << xAction = do
  f <- fAction
  x <- xAction
  return (f x)
