view(...dims) {
        // TODO: validate dims
        let inferredIndex = -1;
        for (let i = 0; i < dims.length; ++i) {
            if (dims[i] === -1) {
                if (inferredIndex !== -1) {
                    throw new Error("Only one dimension can be inferred");
                }
                inferredIndex = i;
            }
        }

        const this_data = this.data;
        if (inferredIndex !== -1) {
            // Some dimension must be inferred
            const productOther = dims.reduce((product, curr, index) => {
                return index !== inferredIndex ? product * curr : product
            }, 1);

            dims[inferredIndex] = this_data.length / productOther;
        }
        return new Tensor(this.type, this_data, dims); // NOTE: uses same underlying storage
    }
Returns a new tensor with the same data as the `self` tensor but of a different `shape`.
@param  {...number} dims the desired size
@returns {Tensor} The tensor with the same data but different shape