IO is a Monad in both Scala and Haskell, and do { line <- getLine; putStrLn line } is the same shape as for { line <- IO.readLine; _ <- IO.println(line) } yield (). That equivalence is where this post starts — with the part of the language that made half the Scala community pick up Cats Effect in the first place.
Here's the thesis, stated plainly: Cats Effect's IO is Haskell's IO, ported to the JVM. Not "inspired by." Ported. The referential transparency, the lazy description-of-a-computation, the run-it-at-the-edge model, bracket, Ref, race, fibers — all of it is the Haskell IO programming model rebuilt on a runtime that wasn't designed for it. Once you delete Future from your mental model, the distance between a Cats Effect program and the equivalent Haskell program is mostly tooling and syntax.
ZIO is the one place that story gets more interesting, and it's why I asked to cover both. ZIO's ZIO[R, E, A] is a genuinely different bet — it folds the environment and the error type into the effect type itself. Haskell makes that same bet too, but it spreads the pieces across different tools: ReaderT for the R, ExceptT or plain exceptions for the E, and increasingly an effect-handler library (effectful, polysemy, fused-effects) when you want the whole thing in one place. Same problem, different decomposition, real trade-offs on both sides.
The map: why Future is the thing to delete, what IO-as-a-value buys you, how errors become just another effect, resource safety, shared state, structured concurrency with a worked example, and finally ZIO against Haskell's MTL. The one neighbor I'm leaving for its own post is streaming — fs2 and ZIO Streams against conduit and streamly is a comparison that deserves the room.