Skip to content

Library reference

Task and device functions

Parallel mapping, device selection and explicit tensor transfers.

These are callable built-ins. spawn, await, on, parallel and try are language syntax, documented in the language reference. Task and device results have types inferred by the compiler. The descriptive names below are reference notation, not generic type declarations to copy into source.

parallelMap

parallelMap(input: [T], callback: fn(T) -> U ! E) -> [U] ! (E | TaskError)

Map supported scalar array elements using CPU workers and return results in input order. A non-fallible callback is allowed; then the error channel is TaskError alone. Application-error families from a fallible callback are preserved alongside task errors. Supported element kinds follow array mapping; callbacks cannot return pending tasks or arbitrary nested collections. Captured values must be supported CPU worker inputs, and captured arrays remain read-only. The operation owns and settles its work before returning. Empty inputs invoke no callbacks. Work already completed is not rolled back after a failure. Execution, cancellation and admission errors can occur; error selection among racing failures is not deterministic. Use it in CPU programs. It is not supported in programs compiled with GPU placement and does not launch one GPU operation per array element.

devices.cpu

devices.cpu() -> CPU device selector

Return the host device selector, without arguments. Use it as a transfer destination or explicit CPU task placement. Available with placement checking and GPU-enabled compilation. It does not start work, copy data or identify a worker thread.

devices.gpu

devices.gpu() -> GPU device selector

devices.gpu(index: constant uint32 literal) -> GPU device selector

Select a GPU exposed by the selected backend; the omitted index is zero. An explicit index must be a nonnegative integer literal fitting uint32, not a runtime expression. A selector does not guarantee that a device exists: dispatch or transfer can fail on unavailable hardware. Available with placement checking and GPU-enabled compilation. Selecting a device does not move tensors or make arbitrary functions eligible for GPU execution.

transfer

transfer(values: completed Tensor[T, ...], target: device selector) -> tensor transfer task

Start an explicit tensor transfer owned by the surrounding parallel scope. Use try await to obtain the completed tensor or propagate TaskError. The element type and shape are preserved. Downloading to devices.cpu() produces a host tensor; awaiting a GPU destination produces a resident tensor, not an implicit download. The input must be a completed numeric tensor, not an array, String or unfinished task. Device compatibility, resource admission and execution can fail. Use only in a parallel scope in a GPU-enabled program. It is not a general conversion or arbitrary object transfer.

CPU example

kalandra
fn double(value: int) -> int:
  value * 2

fn main() -> [int] ! TaskError:
  try parallelMap([2, 4], double)
The result is [4, 8].

GPU example

kalandra
fn total(values: Tensor[float32, ?]) -> float32:
  reduceSum(values)

fn main() -> float32 ! TaskError:
  try parallel:
    cpu = devices.cpu()
    gpu = devices.gpu(0)
    values: Tensor[float32, 2] = tensor([20, 22])
    resident = try await transfer(values, gpu)
    roundTrip = try await transfer(resident, cpu)
    uploaded = try await transfer(roundTrip, gpu)
    try await spawn total(uploaded) on gpu
Compile this program with the Metal commands in the GPU guide. Its numerical result is 42; the Metal entry displays 42280000, the float32 result bits. The extra round trip demonstrates both transfer directions; omit it when your application does not need host access.