from typing import Any
from typing import Callable


def _map(obj: Any, fn: Callable) -> Any:
    """Recursively maps a function to a nested object.

    If the passed object is a list, dictionary, set, or tuple, then all child
    elements are recursively mapped.

    Args:
        obj: The object to map against
        fn: The function to map

    Returns:
        The mutated object
    """
    if isinstance(obj, dict):
        return {k: _map(v, fn) for k, v in obj.items()}
    elif (
        isinstance(obj, list) or isinstance(obj, set) or isinstance(obj, tuple)
    ):
        return [_map(v, fn) for v in obj]
    else:
        return fn(obj)