from collections.abc import Callable
from typing import TypeVar, cast, overload

TNum = TypeVar('TNum', int, float)
T = TypeVar('T')
R = TypeVar('R')


@overload
def add(a: int, /) -> Callable[[TNum], TNum]: ...


@overload
def add(a: float, /) -> Callable[[int | float], float]: ...


@overload
def add(a: int, b: TNum, /) -> TNum: ...


@overload
def add(a: TNum, b: int, /) -> TNum: ...
# rename to value, addend
def add(
    a: int | float, b: int | float | None = None, /,
) -> int | float | Callable[[int | float], int | float] | Callable[[TNum], TNum]:
    if b is None:
        return lambda b: a + b
    return a + b


@overload
def map(data: list[T], callbackfn: Callable[[T], R], /) -> list[R]: ...


@overload
def map(data: Callable[[T], R], /) -> Callable[[list[T]], list[R]]: ...


def map(
    data: list[T] | Callable[[T], R], callbackfn: Callable[[T], R] | None = None, /,
) -> list[R] | Callable[[list[T]], list[R]]:
    if callbackfn is None:
        callbackfn = cast(Callable[[T], R], data)

        def inner(data: list[T], /) -> list[R]:
            return map(data, callbackfn)

        return inner
    data = cast(list[T], data)
    return [callbackfn(item) for item in data]
