or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdindex.mdio.mdresources.mdtype-classes.md

io.mddocs/

0

# IO Monad Operations

1

2

The IO monad is the core effect type in Cats Effect, providing referentially transparent side effect management with full monad operations, error handling, and concurrency support.

3

4

## Capabilities

5

6

### IO Construction

7

8

Core constructors for creating IO values from various sources.

9

10

```scala { .api }

11

/**

12

* Constructs IO values from pure values, side effects, and async operations

13

*/

14

object IO {

15

/** Lift a pure value into the IO context */

16

def pure[A](a: A): IO[A]

17

18

/** Suspend a side-effecting computation */

19

def delay[A](body: => A): IO[A]

20

21

/** Suspend an IO computation for stack safety */

22

def defer[A](thunk: => IO[A]): IO[A]

23

24

/** Create an IO from an async callback */

25

def async[A](k: (Either[Throwable, A] => Unit) => Unit): IO[A]

26

27

/** Create an IO that always fails with the given error */

28

def raiseError[A](e: Throwable): IO[A]

29

30

/** Create an IO that never completes */

31

def never[A]: IO[Nothing]

32

33

/** Create an IO from a Future */

34

def fromFuture[A](fa: IO[Future[A]]): IO[A]

35

36

/** Create an IO from an Either */

37

def fromEither[A](e: Either[Throwable, A]): IO[A]

38

39

/** Create an IO from an Option, failing with NoSuchElementException if None */

40

def fromOption[A](o: Option[A]): IO[A]

41

42

/** Create an IO from an Option with custom error */

43

def fromOption[A](option: Option[A])(orElse: => Throwable): IO[A]

44

45

/** Create an IO from a Try */

46

def fromTry[A](t: Try[A]): IO[A]

47

48

/** Create an IO from an Eval */

49

def eval[A](fa: Eval[A]): IO[A]

50

51

/** Sleep for the specified duration */

52

def sleep(duration: FiniteDuration)(implicit timer: Timer[IO]): IO[Unit]

53

54

/** Create an async IO with pure registration */

55

def asyncF[A](k: (Either[Throwable, A] => Unit) => IO[Unit]): IO[A]

56

57

/** Create a cancelable IO */

58

def cancelable[A](k: (Either[Throwable, A] => Unit) => CancelToken[IO]): IO[A]

59

60

/** Create a ContextShift */

61

def contextShift(ec: ExecutionContext): ContextShift[IO]

62

63

/** Get current fiber trace */

64

def trace: IO[IOTrace]

65

66

/** Create a unit IO */

67

val unit: IO[Unit]

68

69

/** Create an empty Option IO */

70

def none[A]: IO[Option[A]]

71

72

/** Conditional execution */

73

def whenA(cond: Boolean)(action: => IO[Unit]): IO[Unit]

74

75

/** Inverse conditional execution */

76

def unlessA(cond: Boolean)(action: => IO[Unit]): IO[Unit]

77

78

/** Conditional error raising */

79

def raiseWhen(cond: Boolean)(e: => Throwable): IO[Unit]

80

81

/** Inverse conditional error raising */

82

def raiseUnless(cond: Boolean)(e: => Throwable): IO[Unit]

83

}

84

```

85

86

**Usage Examples:**

87

88

```scala

89

import cats.effect._

90

import scala.concurrent.duration._

91

92

// Pure values

93

val pureValue = IO.pure(42)

94

95

// Side effects

96

val sideEffect = IO.delay {

97

println("Hello, World!")

98

"result"

99

}

100

101

// Deferred computation

102

val deferred = IO.defer {

103

if (math.random() > 0.5) IO.pure("heads") else IO.pure("tails")

104

}

105

106

// Async callback

107

val asyncIO = IO.async[String] { callback =>

108

// Simulate async operation

109

new Thread(() => {

110

Thread.sleep(1000)

111

callback(Right("Async result"))

112

}).start()

113

}

114

115

// Error handling

116

val errorIO = IO.raiseError(new RuntimeException("Something went wrong"))

117

118

// Sleep

119

val sleepIO = IO.sleep(2.seconds)

120

```

121

122

### IO Operations

123

124

Core monad operations and transformations.

125

126

```scala { .api }

127

/**

128

* Core IO operations providing monad functionality and transformations

129

*/

130

abstract class IO[+A] {

131

/** Transform the result using a function */

132

def map[B](f: A => B): IO[B]

133

134

/** Chain another IO computation */

135

def flatMap[B](f: A => IO[B]): IO[B]

136

137

/** Replace the result with a constant value */

138

def as[B](b: B): IO[B]

139

140

/** Discard the result */

141

def void: IO[Unit]

142

143

/** Apply an effect and return the original value */

144

def tap[B](f: A => IO[B]): IO[A]

145

146

/** Combine with another IO using a function */

147

def map2[B, C](that: IO[B])(f: (A, B) => C): IO[C]

148

149

/** Sequence this IO after another, discarding the other's result */

150

def *>[B](that: IO[B]): IO[B]

151

152

/** Sequence another IO after this one, discarding that one's result */

153

def <*[B](that: IO[B]): IO[A]

154

155

/** Combine with another IO in parallel */

156

def parProduct[B](that: IO[B]): IO[(A, B)]

157

158

/** Map over both results of a parallel combination */

159

def parMap2[B, C](that: IO[B])(f: (A, B) => C): IO[C]

160

}

161

```

162

163

### Error Handling

164

165

Error handling and recovery operations.

166

167

```scala { .api }

168

/**

169

* Error handling operations for managing failures in IO computations

170

*/

171

abstract class IO[+A] {

172

/** Convert errors to Either */

173

def attempt: IO[Either[Throwable, A]]

174

175

/** Handle errors by providing a recovery function */

176

def handleErrorWith[AA >: A](f: Throwable => IO[AA]): IO[AA]

177

178

/** Handle errors by providing a pure recovery value */

179

def handleError[AA >: A](f: Throwable => AA): IO[AA]

180

181

/** Recover from specific error types */

182

def recover[AA >: A](pf: PartialFunction[Throwable, AA]): IO[AA]

183

184

/** Recover from specific error types with an IO */

185

def recoverWith[AA >: A](pf: PartialFunction[Throwable, IO[AA]]): IO[AA]

186

187

/** Redeem combines map and handleErrorWith */

188

def redeem[B](recover: Throwable => B, map: A => B): IO[B]

189

190

/** RedeemWith combines flatMap and handleErrorWith */

191

def redeemWith[B](recover: Throwable => IO[B], bind: A => IO[B]): IO[B]

192

}

193

```

194

195

**Usage Examples:**

196

197

```scala

198

val program = for {

199

result <- IO.delay(riskyOperation())

200

.handleErrorWith {

201

case _: IOException => IO.pure("default value")

202

case other => IO.raiseError(other)

203

}

204

_ <- IO(println(s"Result: $result"))

205

} yield result

206

207

// Using attempt

208

val safeProgram = riskyIO.attempt.flatMap {

209

case Right(value) => IO(println(s"Success: $value"))

210

case Left(error) => IO(println(s"Error: ${error.getMessage}"))

211

}

212

```

213

214

### Resource Management

215

216

Bracket operations for safe resource acquisition and cleanup.

217

218

```scala { .api }

219

/**

220

* Resource management operations using bracket pattern

221

*/

222

abstract class IO[+A] {

223

/** Bracket pattern for resource management */

224

def bracket[B](use: A => IO[B])(release: A => IO[Unit]): IO[B]

225

226

/** Bracket with exit case information */

227

def bracketCase[B](use: A => IO[B])(release: (A, ExitCase[Throwable]) => IO[Unit]): IO[B]

228

229

/** Always execute finalizer */

230

def guarantee(finalizer: IO[Unit]): IO[A]

231

232

/** Execute finalizer with exit case information */

233

def guaranteeCase(finalizer: ExitCase[Throwable] => IO[Unit]): IO[A]

234

}

235

236

/**

237

* Exit case information for resource cleanup

238

*/

239

sealed trait ExitCase[+E]

240

object ExitCase {

241

case object Completed extends ExitCase[Nothing]

242

case class Error[E](e: E) extends ExitCase[E]

243

case object Canceled extends ExitCase[Nothing]

244

}

245

```

246

247

**Usage Examples:**

248

249

```scala

250

// File resource management

251

def withFile[A](path: String)(use: BufferedReader => IO[A]): IO[A] =

252

IO(new BufferedReader(new FileReader(path)))

253

.bracket(use)(reader => IO(reader.close()))

254

255

// Database connection with error handling

256

def withConnection[A](use: Connection => IO[A]): IO[A] =

257

acquireConnection.bracketCase(use) { (conn, exitCase) =>

258

exitCase match {

259

case ExitCase.Completed => IO(conn.commit()) *> IO(conn.close())

260

case ExitCase.Error(_) => IO(conn.rollback()) *> IO(conn.close())

261

case ExitCase.Canceled => IO(conn.close())

262

}

263

}

264

```

265

266

### Concurrency Operations

267

268

Operations for concurrent execution and fiber management.

269

270

```scala { .api }

271

/**

272

* Concurrency operations for managing concurrent execution

273

*/

274

abstract class IO[+A] {

275

/** Start this IO in a new fiber */

276

def start: IO[Fiber[IO, A]]

277

278

/** Race this IO against another */

279

def race[B](that: IO[B]): IO[Either[A, B]]

280

281

/** Race with detailed fiber information */

282

def racePair[B](that: IO[B]): IO[Either[(A, Fiber[IO, B]), (Fiber[IO, A], B)]]

283

284

/** Set a timeout for this IO */

285

def timeout(duration: FiniteDuration): IO[A]

286

287

/** Set a timeout with a fallback value */

288

def timeoutTo[AA >: A](duration: FiniteDuration, fallback: IO[AA]): IO[AA]

289

290

/** Add a delay before execution */

291

def delayBy(duration: FiniteDuration): IO[A]

292

293

/** Make this IO uncancelable */

294

def uncancelable: IO[A]

295

}

296

297

/**

298

* Fiber represents a running IO computation

299

*/

300

abstract class Fiber[F[_], A] {

301

/** Wait for the fiber to complete */

302

def join: F[A]

303

304

/** Cancel the fiber */

305

def cancel: CancelToken[F]

306

}

307

308

/** Cancellation token */

309

type CancelToken[F[_]] = F[Unit]

310

```

311

312

**Usage Examples:**

313

314

```scala

315

// Concurrent execution

316

val program = for {

317

fiber1 <- IO.delay(expensiveComputation1()).start

318

fiber2 <- IO.delay(expensiveComputation2()).start

319

result1 <- fiber1.join

320

result2 <- fiber2.join

321

} yield (result1, result2)

322

323

// Racing computations

324

val raced = IO.delay(slowOperation()).race(IO.sleep(5.seconds))

325

// Returns Either[String, Unit] - Left if operation completes, Right if timeout

326

327

// Timeout with fallback

328

val withTimeout = longRunningIO.timeoutTo(10.seconds, IO.pure("timeout"))

329

```

330

331

### Safe Execution

332

333

Safe execution methods that return IO for composability.

334

335

```scala { .api }

336

/**

337

* Safe execution methods for running IO computations

338

*/

339

abstract class IO[+A] {

340

/** Run asynchronously with a callback returning IO */

341

def runAsync(cb: Either[Throwable, A] => IO[Unit]): SyncIO[Unit]

342

343

/** Run with cancellation support returning IO */

344

def runCancelable(cb: Either[Throwable, A] => IO[Unit]): SyncIO[CancelToken[IO]]

345

346

/** Convert to other effect types */

347

def to[F[_]](implicit F: LiftIO[F]): F[A]

348

}

349

350

/**

351

* Cancellation token type

352

*/

353

type CancelToken[F[_]] = F[Unit]

354

```

355

356

### Unsafe Operations

357

358

Unsafe operations for executing IO computations (should only be used at application boundaries).

359

360

```scala { .api }

361

/**

362

* Unsafe operations for executing IO - use only at application boundaries

363

*/

364

abstract class IO[+A] {

365

/** Synchronously execute this IO (blocking) */

366

def unsafeRunSync(): A

367

368

/** Asynchronously execute this IO with a callback */

369

def unsafeRunAsync(cb: Either[Throwable, A] => Unit): Unit

370

371

/** Execute with cancellation support */

372

def unsafeRunCancelable(cb: Either[Throwable, A] => Unit): CancelToken[IO]

373

374

/** Execute with a time limit */

375

def unsafeRunTimed(limit: Duration): Option[A]

376

377

/** Convert to Future */

378

def unsafeToFuture(): Future[A]

379

}

380

```

381

382

**Usage Examples:**

383

384

```scala

385

// Only use these at the very edges of your application

386

val result: String = myIO.unsafeRunSync() // Blocks until completion

387

388

myIO.unsafeRunAsync {

389

case Right(value) => println(s"Success: $value")

390

case Left(error) => println(s"Error: ${error.getMessage}")

391

}

392

393

// Convert to Future for interop

394

val future: Future[String] = myIO.unsafeToFuture()

395

```

396

397

## Types

398

399

```scala { .api }

400

/**

401

* The IO monad - represents a suspended side-effecting computation

402

*/

403

abstract class IO[+A] {

404

// Methods defined above

405

}

406

407

/**

408

* Parallel newtype for IO enabling parallel operations

409

*/

410

case class Par[+A](io: IO[A])

411

412

object IO {

413

object Par {

414

def apply[A](io: IO[A]): IO.Par[A]

415

def unwrap[A](par: IO.Par[A]): IO[A]

416

}

417

}

418

419

/**

420

* Fiber represents a running IO computation

421

*/

422

abstract class Fiber[F[_], A] {

423

/** Wait for the fiber to complete */

424

def join: F[A]

425

426

/** Cancel the fiber */

427

def cancel: CancelToken[F]

428

}

429

430

/**

431

* Synchronous IO type for safe operations

432

*/

433

abstract class SyncIO[+A] {

434

def map[B](f: A => B): SyncIO[B]

435

def flatMap[B](f: A => SyncIO[B]): SyncIO[B]

436

def unsafeRunSync(): A

437

}

438

439

/**

440

* IO trace for debugging

441

*/

442

abstract class IOTrace

443

444

/**

445

* Context shift for thread management

446

*/

447

abstract class ContextShift[F[_]] {

448

def shift: F[Unit]

449

def evalOn(ec: ExecutionContext): F[Unit]

450

}

451

452

/**

453

* Timer for time-based operations

454

*/

455

abstract class Timer[F[_]] {

456

def clock: Clock[F]

457

def sleep(duration: FiniteDuration): F[Unit]

458

}

459

```