Chapter 7:
Concurrency

Multisets

set: [E0 E1 E2 ...] => [V0 V1 V2 ...]   or
                    => [V1 V0 V2 ...]   or
                    => [V2 V1 V0 ...]   or
                           etc. etc.
The set primitive returns a new list containing the values of the argument list permuted into an order roughly corresponding to the effort required to compute them. "Easier" values appear earlier in the result list. For example, you can be reasonably sure that
set: [factorial:5  factorial:2] => [2 120]
We say reasonably sure because the measure of "effort" required to compute a value depends on a number of variable and dynamic factors in the host system. It may help to think of set more like a special form that concurrently evaluates its arguments and appends the values, as they become available, to the end of the result list. How that concurrency is handled by the system plays a role in which computations finish first. To continue our example, if we are executing this set expression on a single processor system, we might expect that the two factorial expressions are somehow implicitly multitasked. Since neither expression is that complicated, it is conceivable that both expressions could be evaluated in a single time slice quantum. Which one should then be selected for "promotion" to the head of the result list? The answer is that the system has some notion of fairness that allows either value to be a suitable candidate. In actuality, Daisy's concurrency granularity is fine enough to easily distinguish the effort to compute our two example values. For most practical purposes, set provides a reasonably accurate way to order values by computation time.

The interaction of set with expressions that return list values can be confusing. Suppose we have a function called list-of-primes that computes the list of the first N prime numbers. In the expression:

set: [list-of-primes:50  list-of-primes:2]
the novice Daisy programmer may be surprised to see the list of 50 primes appearing before the list of 2 primes! But remember, they only asked for the list and not the contents of the list, insofar as the set expression is concerned. Since Daisy is demand-driven, it will only evaluate as much as is needed to compute the outer structure of the primes lists. It's only when the result of the set is accessed that any primes may actually be computed. To get around this, you can use coercion operators to achieve the desired results:
set: [force:list-of-primes:50  force:list-of-primes:2]

A common use of set with list values is to merge one or more lists together by the order in which their elements compute. See Appendix B for an example.

Although many Daisy primitives allow concurrency as an implementation option, set is the only one that by definition implies it. Therefore it is often applied just for its concurrent effects and its result is discarded. Typical uses of this sort are to concurrently "drive" or strobe a set of streams.

The behavior of set is intricately tied to the notion of suspensions underlying most list structures. See Appendix A, Suspending Construction, for details.