norm(p = 'fro', dim = null, keepdim = false) {
        if (p === 'fro') {
            // NOTE: Since we only support integer dims, Frobenius norm produces the same result as p=2.
            p = 2;
        } else if (typeof p === 'string') {
            throw Error(`Unsupported norm: ${p}`);
        }

        const this_data = this.data;
        const fn = (a, b) => a + (b ** p);

        if (dim === null) {
            // @ts-ignore
            const val = this_data.reduce(fn, 0) ** (1 / p);
            return new Tensor(this.type, [val], []);
        }

        const [type, result, resultDims] = reduce_helper(fn, this, dim, keepdim);

        if (p !== 1) {
            for (let i = 0; i < result.length; ++i) {
                result[i] = result[i] ** (1 / p);
            }
        }
        return new Tensor(type, result, resultDims);
    }
Returns the matrix norm or vector norm of a given tensor.
@param {number|string} [p='fro'] The order of norm
@param {number} [dim=null] Specifies which dimension of the tensor to calculate the norm across.
If dim is None, the norm will be calculated across all dimensions of input.
@param {boolean} [keepdim=false] Whether the output tensors have dim retained or not.
@returns {Tensor} The norm of the tensor.