Caches the result of the provided function.

def memoize(fn=None):
    """Caches the result of the provided function."""
    cache = { }
    arg_hash_fn = fn_arg_hash_function(fn)

    def decorated(*args, **kwargs):
        try:
            hash_ = arg_hash_fn(*args, **kwargs)
        except TypeError:
            return fn(*args, **kwargs)

        try:
            return cache[hash_]
        except KeyError:
            return_val = fn(*args, **kwargs)
            cache[hash_] = return_val
            return return_val
    _functools.update_wrapper(decorated, fn)

    return decorated