{-# LANGUAGE LambdaCase #-}

import Control.Monad ((>=>))
import Data.Function (fix)
import System.Environment (getArgs)
import System.IO (hPutStrLn, stderr)

main :: IO ()
main = getArgs >>=                       -- Get command line arguments.
  (\ case                                -- Check if there are no arguments.
    [] -> hPutStrLn stderr "(reading numbers from stdin...)" >>
      (words >=> lines) <$> getContents  -- Read STDIN, break into tokens by whistspace.
    args -> return (args >>= words)      -- Break arguments by whitespace as well.
  ) >>= mapM_                            -- Iterate over input arguments.
  ( putStrLn .                           -- Display list on console.
    unwords .                            -- Join the list by whitespace.
    fmap show .                          -- Convert all integers to base-10 strings.
    ( fix $ \ loop stack n0 ->           -- Begin generating a lazy list.
      (n0 :: Int) :                      -- Place the element into the result list.
      if n0 <= 1 then [] else            -- Break the loop if n has converged to zero.
      if n0 `elem` stack then [] else    -- Break the loop if we found a cycle.
      loop (n0 : stack) $                -- Otherwise, push this element onto the stack and loop.
      let (n, rem) = divMod n0 2 in      -- Check for even or odd.
      if rem == 0 then n else 3 * n0 + 1 -- The Collatz function.
    ) [] .                               -- Initialize the "fix" loop with an empty stack.
    read                                 -- Parse each input argument.
  )
