如何在Cats中实现以下三种while(true)无限循环?
Great question! In Cats (and functional Scala more broadly), we avoid mutable variables and imperative while loops in favor of pure, immutable constructs—especially since your examples involve effectful operations like doSomething(), which we'll model using Cats' IO type (the standard way to handle side effects in Cats). Let's break down each case:
while(true) { doSomething() }) If doSomething() is an effectful operation (e.g., printing to the console, making an API call), the most idiomatic approach is to use IO.foreverM to run it indefinitely:
import cats.effect.IO import cats.effect.unsafe.implicits.global // Example effectful operation val doSomething: IO[Unit] = IO(println("Executing doSomething...")) // The infinite loop val infiniteLoop: IO[Unit] = doSomething.foreverM // Run the loop (only in a standalone app; use Ctrl+C to stop) infiniteLoop.unsafeRunSync()
Alternatively, if you prefer explicit recursion (which foreverM handles under the hood), you can define a tail-recursive function:
def infiniteLoop: IO[Unit] = doSomething.flatMap(_ => infiniteLoop)
var i = 1; while(true) { i +=1; doSomething() }) Instead of using a mutable var, we pass the state (the value of i) through recursive calls. Here's a clean tail-recursive IO implementation:
def loopWithIncrement(currentI: Int): IO[Unit] = val nextI = currentI + 1 doSomething.flatMap(_ => loopWithIncrement(nextI)) // Start the loop with i=1 val startLoop: IO[Unit] = loopWithIncrement(1) startLoop.unsafeRunSync()
For a more concise approach, use IO.iterate to generate the sequence of incremented values and evalMap to run the effect for each:
import cats.syntax.all._ val startLoop: IO[Unit] = IO.iterate(1)(_ + 1).evalMap(_ => doSomething).foreverM
var x=1; var y=2; while(true) { x=someCalculation(); y=otherCalculation(); doSomething() }) We bundle variables into an immutable structure (tuple or case class) to pass as state through recursion. Using a case class makes the code more readable for complex state:
Using a Tuple (for simple state)
// Example pure calculations def someCalculation(x: Int): Int = x * 2 def otherCalculation(y: Int): Int = y + 3 def loopWithVars(currentX: Int, currentY: Int): IO[Unit] = val newX = someCalculation(currentX) val newY = otherCalculation(currentY) doSomething.flatMap(_ => loopWithVars(newX, newY)) // Start with x=1, y=2 val startLoop: IO[Unit] = loopWithVars(1, 2) startLoop.unsafeRunSync()
Using a Case Class (for cleaner state management)
case class AppState(x: Int, y: Int) def updateState(state: AppState): AppState = AppState(someCalculation(state.x), otherCalculation(state.y)) def loopWithState(state: AppState): IO[Unit] = doSomething.flatMap(_ => loopWithState(updateState(state))) val startLoop: IO[Unit] = loopWithState(AppState(1, 2))
If your calculations are effectful (e.g., read from a database), wrap them in IO and use a for-comprehension:
def someCalculation(x: Int): IO[Int] = IO(x * 2) // Effectful calculation def otherCalculation(y: Int): IO[Int] = IO(y + 3) def loopWithVars(currentX: Int, currentY: Int): IO[Unit] = for { newX <- someCalculation(currentX) newY <- otherCalculation(currentY) _ <- doSomething _ <- loopWithVars(newX, newY) } yield ()
内容的提问来源于stack exchange,提问作者Piu130

