import torch


def _reduce_list(val_list, red_func=torch.cat):
    """
    Applies reduction function to given list. If each element in the list is
    a Tensor, applies reduction function to all elements of the list, and returns
    the output Tensor / value. If each element is a tuple, applies reduction
    function to corresponding elements of each tuple in the list, and returns
    tuple of reduction function outputs with length matching the length of tuple
    val_list[0].
    """
    if isinstance(val_list[0], torch.Tensor):
        return red_func(val_list)
    assert isinstance(val_list[0], tuple), "Elements to be reduced can only be"
    "either Tensors or tuples containing Tensors."
    final_out = []
    for i in range(len(val_list[0])):
        final_out.append(_reduce_list([val_elem[i] for val_elem in val_list], red_func))
    return tuple(final_out)