Search code examples
scalaiocats-effect

How to exit from For-Comprehension with IO Monad


I want to make infinite read print cycle with exit when user enter "stop" and make readLn async.

import cats.effect.{ExitCode, IO, IOApp, Timer}

import scala.concurrent.duration._
import scala.io.StdIn
import scala.language.postfixOps
import cats.implicits._

object ReadWrite extends IOApp {
  val readLn: IO[String] = IO(StdIn.readLine())
  val readWriteName: IO[Nothing] = for {
    _     <- IO(println("write your name: "))
    name  <- readLn
    _     <- IO(println(s"Hello, $name"))
    t     <- name match {
      case "stop" => ???
      case _      =>  readWriteName
    }
  } yield t

  def run(args: List[String]): IO[ExitCode] =
    for {
      _ <- (Timer[IO].sleep(1 millisecond) *> readWriteName).start
      _ <- Timer[IO].sleep(100 second)
    } yield ExitCode.Success
}

I tried to use IO(println(s"Buy Buy")) but there is error message:

Error:(20, 11) type mismatch;
 found   : t.type (with underlying type Unit)
 required: Nothing
  } yield t

How to make exit without error?

Also I want to execute IO in another thread, readLn for example.


Solution

  • Change type of readWriteName to IO[Unit].

    val readWriteName: IO[Unit] = for {
      _     <- IO(println("write your name: "))
      name  <- readLn
      _     <- IO(println(s"Hello, $name"))
      t     <- name match {
        case "stop" => IO(println(s"Buy Buy"))
        case _      =>  readWriteName
      }
    } yield t
    

    Regarding threads look at Cats-effect and asynchronous IO specifics


    Try

      val readWriteName: IO[String] = for {
        _     <- IO(println("write your name: "))
        name  <- readLn
        _     <- IO(println(s"Hello, $name"))
        _     <- name match {
          case "stop" => IO(println(s"Buy Buy"))
          case _      =>  readWriteName
        }
      } yield name