import System.IO.Unsafe ( unsafePerformIO )

main = print (runIO myReadLines)

type World = ()

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

instance Monad MyIO where
  return x = MyIO (\world -> (x,world))

  MyIO action >>= f
    = MyIO (\world -> case action world of
                       (x,world') -> let (MyIO action') = f x
                                      in action' world')

runIO :: MyIO a -> a
runIO (MyIO action) = fst (action ())

lift :: IO a -> MyIO a
lift action = MyIO (\world -> let x = unsafePerformIO action
                               in seq x (x,world))

myPutStrLn :: String -> MyIO ()
myPutStrLn = lift . putStrLn

myGetLine :: MyIO String
myGetLine = lift getLine

myReadLines :: MyIO ()
myReadLines = do
  l <- myGetLine
  if l=="." then return ()
   else myReadLines >> myPutStrLn l


data NoIO a = NoIO (World -> a)

instance Monad NoIO where
  return x = NoIO (\_ -> x)

  NoIO action >>= f = NoIO (\world -> case f (action world) of
                                        NoIO action' -> action' world)

runNoIO :: NoIO a -> a
runNoIO (NoIO action) = action ()

nolift :: IO a -> NoIO a
nolift action = NoIO (\_ -> unsafePerformIO action)

noGetLine :: NoIO String
noGetLine = nolift getLine

noPutStrLn :: String -> NoIO ()
noPutStrLn s = nolift (putStrLn s)

noeval :: NoIO ()
noeval = do
  x <- noGetLine
  noPutStrLn "42"      -- never printed
  noPutStrLn (show x)

noorder :: NoIO ()
noorder = do
  x <- noGetLine
  y <- noGetLine       -- executed first
  noPutStrLn (y++x)
                                 


