public static function reduce(callable $f, $xs, $initial = null)
    {
        if (is_array($xs)) {
            $initial = $initial !== null ? $initial : array_shift($xs);
            return array_reduce($xs, $f, $initial);
        }
        if ($xs instanceof \Iterator) {
            $xs->rewind();
            if (!$xs->valid()) {
                return $initial;
            }
            $acc = $initial;
            if ($acc === null) {
                $acc = $xs->current();
                $xs->next();
            }
            for (; $xs->valid(); $xs->next()) {
                $acc = call_user_func($f, $acc, $xs->current());
            }
            return $acc;
        }
        throw new \InvalidArgumentException();
    }