protected static function memoize(Callable $f)
    {
        return function(...$args) use ($f) {
            static $cache;

            if ($cache === null)
                $cache = [];

            $key = serialize($args);

            if (array_key_exists($key, $cache)) {
                return $cache[$key];
            } else {
                $result = call_user_func_array($f, $args);
                $cache[$key] = $result;

                return $result;
            }
        };
    }