A callback is a function handed to an operation now so it can handle a value later. In a non-blocking representation, a Future does not expose a blocking get; it accepts an A => Unit callback, also called a continuation, and invokes it when A has been computed. The callback need not run immediately. section 7.3.4
This shifts the boundary of an asynchronous program. A callback-based byte source returns immediately, while its callback receives either an error or the requested bytes when the I/O subsystem finishes. Calling such APIs directly spreads completion handlers through application code; wrapping them as Par values preserves a compositional interface. section 13.5
A callback adapter follows a small, explicit path:
- Accept the callback expected by Par.async. section 13.5
- Start the underlying asynchronous request and pass it a completion handler. section 13.10
- Have completed and failed forward a Right result or Left error to that callback. section 13.10
- Suspend the resulting Par action when it must participate in a Free program. section 13.10
Wrapping an asynchronous read
A Source.readBytes call takes a callback of type Either[Throwable, Array[Byte]] => Unit. nonblockingRead passes Par.async a function that calls source.readBytes(numBytes, cb). The source retains cb until bytes or an error are available; the surrounding code receives a Par value instead of manually coordinating completion. section 13.5
def nonblockingRead(source: Source, numBytes: Int):
Par[Either[Throwable, Array[Byte]]] =
async: (cb: Either[Throwable, Array[Byte]] => Unit) =>
source.readBytes(numBytes, cb)
def readPar(source: Source, numBytes: Int):
Free[Par, Either[Throwable, Array[Byte]]] =
Suspend(nonblockingRead(source, numBytes))
Shows the direct forwarding adapter from a callback-based byte source into Par, then into Free[Par, ...]. section 13.5
Callbacks are imperative at the implementation boundary because A => Unit uses its input to perform an effect rather than return a useful result. That does not make the public Par API impure: the Future representation is opaque, so its local effects are not observable by code using Par. Higher-level operations can then combine asynchronous results; for example, map2 uses an Actor to coordinate whichever callback arrives first and invoke a combined callback once both values exist. section 7.3.4


















