code: def ed(fn, iterable, *args, **kwargs):
      
      if hasattr(iterable, '__len__'):
          return iterable.__class__(fn(iterable, *args, **kwargs))
      else:
          return tuple(fn(iterable, *args, **kwargs))
docs: 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.