def swap_element(sequence, idx, replacement):
    """
    Returns a copy of the sequence with the ith value swapped with the replacement value. Useful for immutable values
    such as strings.

    :param sequence: the original immutable sequence.
    :param idx: the index of the sequence element to swap (use negative index to count from last element of the sequence.)
    :param replacement: the replacement value the ith element of the sequence

    :return: a copy of the original sequence with the ith element replaced by the replacement value
    """
    seq_length = len(sequence)

    if seq_length == 0: # return a copy of the empty sequence
        raise ValueError('cannot swap value in an empty sequence')

    if idx < 0:
        use_idx = seq_length + idx
    else:
        use_idx = idx

    if use_idx < 0 or use_idx >= seq_length:
        raise IndexError('index out of range')

    if seq_length == 1: # swap element in a single element sequence
        return replacement
    elif use_idx == 0:  # swap first element
        return replacement + sequence[1:]
    elif use_idx == seq_length-1:   # swap last element
        return sequence[:use_idx] + replacement
    else:   # swap an element in the middle of a sequence
        return sequence[:use_idx] + replacement + sequence[use_idx + 1:]