function reduce( arr, initial, reducer, thisArg ) {
	if ( !isFunction( reducer ) ) {
		throw new TypeError( format( 'invalid argument. Third argument must be a function. Value: `%s`.', reducer ) );
	}
	if ( isndarrayLike( arr ) ) { // note: assertion order matters here, as an ndarray-like object is also array-like
		return ndarrayFcn( ndarraylike2object( arr ), initial, reducer, thisArg ); // eslint-disable-line max-len
	}
	if ( isArrayLikeObject( arr ) ) {
		return arrayFcn( arraylike2object( arr ), initial, reducer, thisArg );
	}
	throw new TypeError( format( 'invalid argument. First argument must be an array-like object or an ndarray. Value: `%s`.', arr ) );
}
Applies a function against an accumulator and each element in an array and returns the accumulated result.

## Notes

-   The applied function is provided the following arguments:

    -   **accumulator**: accumulated value.
    -   **value**: array element.
    -   **index**: element index.
    -   **arr**: input array.

@param {(ArrayLikeObject|ndarray)} arr - input array
@param {*} initial - initial value
@param {Function} reducer - reduction function
@param {*} [thisArg] - reduction function execution context
@throws {TypeError} first argument must be an array-like object or an ndarray
@throws {TypeError} third argument must be a function
@returns {*} accumulated result

@example
function sum( acc, value ) {
    return acc + value;
}

var arr = [ 1, 2, 3, 4 ];

var out = reduce( arr, 0, sum );
// returns 10

@example
var naryFunction = require( '@stdlib/utils/nary-function' );
var add = require( '@stdlib/number/float64/base/add' );
var array = require( '@stdlib/ndarray/array' );

var opts = {
    'dtype': 'generic'
};
var arr = array( [ [ 1, 2, 3 ], [ 4, 5, 6 ] ], opts );

var out = reduce( arr, 0, naryFunction( add, 2 ) );
// returns 21