Asynchronous programming represents work that can proceed independently of its caller, allowing a program to describe computation without immediately waiting for completion. Purely functional designs treat asynchronous computations as values and defer execution to a separate interpreter. section 7.0 section 7.5
A functional asynchronous design emphasizes:
- Avoiding shared mutable memory, which can produce race conditions, deadlocks, poor testability, and weak scalability. section 7.0
- Combining computations with operations such as map, flatMap, and sequence before explicitly waiting for results. section 7.1.1 section 7.6
- Separating a computation's description from the interpreter that runs it, so programs remain composable and reasoning stays focused on pure values. section 7.5 section 7.6
Delaying the wait
A parallel sum can construct two asynchronous computations, sumL and sumR, and combine them only after explicitly requesting their results. Calling get too early exposes waiting and can prevent the intended parallel execution; delaying get preserves the asynchronous structure until the boundary where the result is needed. section 7.1.1
Listing 13.5 Defining our Async type
enum Async[A]:
case Return(a: A)
case Suspend(resume: Par[A])
case FlatMap[A, B](sub: Async[A],
k: A => Async[B]) extends Async[B]
def flatMap[B](f: A => Async[B]): Async[B] =
FlatMap(this, f)
def map[B](f: A => B): Async[B] =
flatMap(a => Return(f(a)))
Inspect the Async data type: Return represents a completed value, Suspend embeds a Par computation, and FlatMap sequences asynchronous steps. section 13.4



























