Bogdan Vakulenko
Bogdan Vakulenko

Reputation: 3390

How to configure Cats Timer on abstract effect type

Let's say I have a following method signature in a project using Cats-effect and tagless final approach:

def schedule[F[_]: Applicative : Async: Timer]

I'm trying to schedule an operation on a schedule method call using pure FP.

I tried this way:

Timer[F].sleep(FiniteDuration(10, TimeUnit.SECONDS)) *> {
    Applicative[F].pure(println("tick"))
}

but it didn't work, because effect println("tick") gets executed on Timer initialisation stage.

How can I make it works properly?

Can I also create some kind of recursive construction in order to repeat my scheduled operation each 10 seconds?

Upvotes: 3

Views: 1007

Answers (2)

Hunor Kovács
Hunor Kovács

Reputation: 1294

Just using the above to write a full example. Credit to them.

package com.example.timerapp

import cats.Applicative
import cats.effect.{Async, ExitCode, IO, IOApp, Timer}
import cats.syntax.apply._
import cats.syntax.flatMap._
import scala.concurrent.duration._
import java.time.Instant

object TimerApp extends IOApp {

  override def run(args: List[String]): IO[ExitCode] = {
    repeat[IO].as(ExitCode.Success)
  }

  def schedule[F[_]: Applicative: Async: Timer]: F[Unit] =
    Timer[F].sleep(1 second) *> {
      Async[F].delay(println(Instant.now.toString))
    }

  def repeat[F[_]: Async: Timer]: F[Unit] =
    schedule[F] >> repeat

}

Upvotes: 3

Jasper-M
Jasper-M

Reputation: 15086

Applicative[F].pure doesn't delay the effect. It only lifts a pure value into F. Since you have an Async context bound I would suggest Async[F].delay(println("tick")).

You can easily call it recursively like this:

def schedule[F[_]: Async: Timer]: F[Unit]

def repeat[F[_]: Async: Timer]: F[Unit] =
  schedule >> repeat

Upvotes: 5

Related Questions