We have seen how the spawn expression allows us to evaluate an expression in a new thread:

region rc {
    spawn (1 + 2) @ rc

This allows us to write concurrent and parallel programs using structured concurrency. The downside is that we must manually coordinate communication between threads using channels. If we want parallelism, but not concurrency, a more light-weight approach is to use the par-yield expression:

par (x <- e1; y <- e2; z <- e3)
    yield x + y + z

which evaluates e1, e2, and e3 in parallel and binds their results to x, y, and z.

We can use par-yield to write a parallel function:

def parMap(f: a -> b, l: List[a]): List[b] = match l {
    case Nil     => Nil
    case x :: xs =>
        par (r <- f(x); rs <- parMap(f, xs))
            yield r :: rs

This function will evaluate f(x) and parMap(f, xs) in parallel.

Note: The par-yield construct only works with pure expressions.

If you want to run effectful operations in parallel, you must use explicit regions and threads.