Memoized Y combinator.

    .. testsetup::

        from proso.func import memo_Y

    .. testcode::

        @memo_Y
        def fib(f):
            def inner_fib(n):
                if n > 1:
                    return f(n - 1) + f(n - 2)
                else:
                    return n
            return inner_fib

        print(fib(100))

    .. testoutput::

        354224848179261915075

def memo_Y(f):
    """
    Memoized Y combinator.

    .. testsetup::

        from proso.func import memo_Y

    .. testcode::

        @memo_Y
        def fib(f):
            def inner_fib(n):
                if n > 1:
                    return f(n - 1) + f(n - 2)
                else:
                    return n
            return inner_fib

        print(fib(100))

    .. testoutput::

        354224848179261915075
    """
    sub = {}

    def Yf(*args):
        hashable_args = tuple([repr(x) for x in args])
        if args:
            if hashable_args not in sub:
                ret = sub[hashable_args] = f(Yf)(*args)
            else:
                ret = sub[hashable_args]
            return ret
        return f(Yf)()
    return f(Yf)