If ``fn`` maps ``iterable`` to a generator (e.g. :func:`flatten` and
    others below), ``ed`` will consume the result and produce a tuple or list.

    If ``iterable`` has a finite length (e.g. tuples, lists), uses the
    same type to consume it. If not (e.g. generators), use a tuple.

    The cypy functions have an `ed` member to make this convenient.

    Why `ed`? Because its the past tense -- take the lazy generator and
    consume it by creating a tuple or list out of it.

def ed(fn, iterable, *args, **kwargs):
    """If ``fn`` maps ``iterable`` to a generator (e.g. :func:`flatten` and
    others below), ``ed`` will consume the result and produce a tuple or list.

    If ``iterable`` has a finite length (e.g. tuples, lists), uses the
    same type to consume it. If not (e.g. generators), use a tuple.

    The cypy functions have an `ed` member to make this convenient.

    Why `ed`? Because its the past tense -- take the lazy generator and
    consume it by creating a tuple or list out of it.
    """
    if hasattr(iterable, '__len__'):
        return iterable.__class__(fn(iterable, *args, **kwargs))
    else:
        return tuple(fn(iterable, *args, **kwargs))