function reduce (mat, dim, callback) {
  const size = Array.isArray(mat) ? arraySize(mat) : mat.size()
  if (dim < 0 || (dim >= size.length)) {
    // TODO: would be more clear when throwing a DimensionError here
    throw new IndexError(dim, size.length)
  }

  if (isMatrix(mat)) {
    return mat.create(_reduce(mat.valueOf(), dim, callback), mat.datatype())
  } else {
    return _reduce(mat, dim, callback)
  }
}
Reduce a given matrix or array to a new matrix or
array with one less dimension, applying the given
callback in the selected dimension.
@param {Array | Matrix} mat
@param {number} dim
@param {Function} callback
@return {Array | Matrix} res