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))
}
RangeAnd receives a range, a batch count n, and a range predicate function f,
divides the range into batches, and invokes the range predicate for each of
these batches sequentially, covering the half-open interval from low to high,
including low but excluding high.

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.

RangeAnd returns by combining all return values with the && operator.

RangeAnd 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))
}