@classmethod
def ap(cls, f, *monads, **kwarg_monads):
    """
        Monad.ap(f, *args, **kwargs) allows you to call a pure
        function within a Monad.

        A normal function like `f(x): x + 1` can be made to take a
        Maybe and return a Maybe without any boilerplating:

        >>> from fp.monads.maybe import Maybe, Just, Nothing
        >>> Maybe.ap(lambda x: x+1, Just(1))
        Just(2)

        >>> Maybe.ap(lambda x: x+1, Nothing)
        Nothing

        Here's an example with an add function:

        >>> import operator
        >>> Maybe.ap(operator.add, Just(1), Just(2))
        Just(3)

        >>> Maybe.ap(operator.add, Nothing, Just(2))
        Nothing

        >>> Maybe.ap(operator.add, Just(1), Nothing)
        Nothing

        It even works with kwargs:

        >>> from datetime import timedelta
        >>> Maybe.ap(timedelta, days=Just(1), seconds=Just(60))
        Just(datetime.timedelta(1, 60))
        """
    argsM = cls.sequence(monads)
    kwargsM = cls.sequence_dict(kwarg_monads)
    return argsM.bind(lambda args: kwargsM.bind(lambda kwargs: cls.ret(f(*
        args, **kwargs))))
