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