You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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:

1. Simple Infinite Loop (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)
2. Infinite Loop with Incrementing Variable (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
3. Infinite Loop with Multiple Independent Variables (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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:34:32