Control-oriented parallelism is typically expressed by a sequence of strategy applications composed with par and seq that specifies which subexpressions of a function are to be evaluated in parallel, and in what order. The sequence is loosely termed a strategy, and is invoked by either the demanding or the sparking function. The Haskell flip function simply reorders a binary function's parameters.
demanding, sparking :: a -> () -> a demanding = flip seq sparking = flip par
The control-oriented parallelism of pfib can be expressed as follows using demanding. Sections * and * contain examples using sparking
pfib n
| n <= 1 = 1
| otherwise = (n1+n2+1) `demanding` strategy
where
n1 = pfib (n-1)
n2 = pfib (n-2)
strategy = rnf n1 `par` rnf n2
If we wish to avoid explicitly naming the result of a function, it is sometimes convenient to apply a control-oriented strategy with using. Quicksort is one example, and as before the two subexpressions, losort and hisort are selected for parallel evaluation.
quicksortS (x:xs) = losort ++ (x:hisort) `using` strategy
where
losort = quicksortS [y|y <- xs, y < x]
hisort = quicksortS [y|y <- xs, y >= x]
strategy result = rnf losort `par`
rnf hisort `par`
rnf result