4

This is a toy Scala program, that reads 10 numbers from the console and adds 1 to each prints them out:

import cats._
import cats.effect._
import cats.implicits._

object Main extends IOApp {
  def printLine[A](x: A)(implicit show: Show[A]): IO[Unit] =
    IO(println(show.show(x)))

  def readLine(): IO[String] =
    IO(scala.io.StdIn.readLine())

  def readInts(n: Int): IO[List[Int]] =
    List.fill(n)(readLine().map(_.toInt)).sequence

  override def run(args: List[String]): IO[ExitCode] = {
    for {
      list <- readInts(10)
      i <- list
      _ <- printLine(i + 1)
    } yield ExitCode.Success
  }
}

The above code does not compile. I get:

[error]  found   : cats.effect.IO[cats.effect.ExitCode]
[error]  required: scala.collection.GenTraversableOnce[?]
[error]       _ <- printLine(i + 1)

What am I doing wrong?

0

1 Answer 1

5

Your for comprehension is for your IO, but you're mixing it with List. To make it a bit clearer we can expand the for comprehension, which won't compile for the same reason that you can't flatten a List into an IO:

readInts(10).flatMap(list => list.flatMap(i => printLine(i + 1).map(_ => ExitCode.Success)))

Instead, try this:

for {
  list <- readInts(10)
  _ <- list.traverse(i => printLine(i + 1))
} yield ExitCode.Success

Note that this is essentially the same as:

for {
  list <- readInts(10)
  _ <- list.map(i => printLine(i + 1)).sequence
} yield ExitCode.Success

traverse just compresses the map and sequence steps into one. In either case, now your for comprehension is properly limited to IO.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.