func RangeReduce(
	low, high, n int,
	reduce func(low, high int) interface{},
	join func(x, y interface{}) interface{},
) interface{} {
	var recur func(int, int, int) interface{}
	recur = func(low, high, n int) interface{} {
		switch {
		case n == 1:
			return reduce(low, high)
		case n > 1:
			batchSize := ((high - low - 1) / n) + 1
			half := n / 2
			mid := low + batchSize*half
			if mid >= high {
				return reduce(low, high)
			}
			left := recur(low, mid, half)
			right := recur(mid, high, n-half)
			return join(left, right)
		default:
			panic(fmt.Sprintf("invalid number of batches: %v", n))
		}
	}
	return recur(low, high, internal.ComputeNofBatches(low, high, n))
}
RangeReduce receives a range, a batch count, a range reduce function, and a
join function, divides the range into batches, and invokes the range reducer
for each of these batches sequentially, covering the half-open interval from
low to high, including low but excluding high. The results of the range
reducer invocations are then combined by repeated invocations of join.

The range is specified by a low and high integer, with low <= high. The
batches are determined by dividing up the size of the range (high - low) by
n. If n is 0, a reasonable default is used that takes runtime.GOMAXPROCS(0)
into account.

RangeReduce panics if high < low, or if n < 0.
package sequential
import (
	"fmt"
	"github.com/exascience/pargo/internal"
)
func Reduce(
	join func(x, y interface{}) interface{},
	firstFunction func() interface{},
	moreFunctions ...func() interface{},
) interface{} {
	result := firstFunction()
	for _, f := range moreFunctions {
		result = join(result, f())
	}
	return result
}
func ReduceFloat64(
	join func(x, y float64) float64,
	firstFunction func() float64,
	moreFunctions ...func() float64,
) float64 {
	result := firstFunction()
	for _, f := range moreFunctions {
		result = join(result, f())
	}
	return result
}
func ReduceFloat64Sum(functions ...func() float64) float64 {
	result := float64(0)
	for _, f := range functions {
		result += f()
	}
	return result
}
func ReduceFloat64Product(functions ...func() float64) float64 {
	result := float64(1)
	for _, f := range functions {
		result *= f()
	}
	return result
}
func ReduceInt(
	join func(x, y int) int,
	firstFunction func() int,
	moreFunctions ...func() int,
) int {
	result := firstFunction()
	for _, f := range moreFunctions {
		result = join(result, f())
	}
	return result
}
func ReduceIntSum(functions ...func() int) int {
	result := 0
	for _, f := range functions {
		result += f()
	}
	return result
}
func ReduceIntProduct(functions ...func() int) int {
	result := 1
	for _, f := range functions {
		result *= f()
	}
	return result
}
func ReduceString(
	join func(x, y string) string,
	firstFunction func() string,
	moreFunctions ...func() string,
) string {
	result := firstFunction()
	for _, f := range moreFunctions {
		result = join(result, f())
	}
	return result
}
func ReduceStringSum(functions ...func() string) string {
	result := ""
	for _, f := range functions {
		result += f()
	}
	return result
}
func Do(thunks ...func()) {
	for _, thunk := range thunks {
		thunk()
	}
}
func And(predicates ...func() bool) bool {
	result := true
	for _, predicate := range predicates {
		result = result && predicate()
	}
	return result
}
func Or(predicates ...func() bool) bool {
	result := false
	for _, predicate := range predicates {
		result = result || predicate()
	}
	return result
}
func Range(
	low, high, n int,
	f func(low, high int),
) {
	var recur func(int, int, int)
	recur = func(low, high, n int) {
		switch {
		case n == 1:
			f(low, high)
		case n > 1:
			batchSize := ((high - low - 1) / n) + 1
			half := n / 2
			mid := low + batchSize*half
			if mid >= high {
				f(low, high)
				return
			}
			recur(low, mid, half)
			recur(mid, high, n-half)
		default:
			panic(fmt.Sprintf("invalid number of batches: %v", n))
		}
	}
	recur(low, high, internal.ComputeNofBatches(low, high, n))
}
func RangeAnd(
	low, high, n int,
	f func(low, high int) bool,
) bool {
	var recur func(int, int, int) bool
	recur = func(low, high, n int) bool {
		switch {
		case n == 1:
			return f(low, high)
		case n > 1:
			batchSize := ((high - low - 1) / n) + 1
			half := n / 2
			mid := low + batchSize*half
			if mid >= high {
				return f(low, high)
			}
			b0 := recur(low, mid, half)
			b1 := recur(mid, high, n-half)
			return b0 && b1
		default:
			panic(fmt.Sprintf("invalid number of batches: %v", n))
		}
	}
	return recur(low, high, internal.ComputeNofBatches(low, high, n))
}
func RangeOr(
	low, high, n int,
	f func(low, high int) bool,
) bool {
	var recur func(int, int, int) bool
	recur = func(low, high, n int) bool {
		switch {
		case n == 1:
			return f(low, high)
		case n > 1:
			batchSize := ((high - low - 1) / n) + 1
			half := n / 2
			mid := low + batchSize*half
			if mid >= high {
				return f(low, high)
			}
			b0 := recur(low, mid, half)
			b1 := recur(mid, high, n-half)
			return b0 || b1
		default:
			panic(fmt.Sprintf("invalid number of batches: %v", n))
		}
	}
	return recur(low, high, internal.ComputeNofBatches(low, high, n))
}