Add new itertool: `side_effect()`

Passes through the iterable, but invokes a function for each item iterated over.

Can be useful for lazy counting, logging, collecting data, or updating progress bars, anything un-pure.

`fn` must be a function that takes a single argument.  Its return value will be discarded.

Examples:

    >>> from more_itertools import take, consume, side_effect
    >>> iterable = take(3, range(10))
    >>> iterable = side_effect(print, iterable)
    >>> consume(iterable)
    0
    1
    2

Example for collecting data as it streams through:

    >>> iterable = take(3, range(10))
    >>> c = set()
    >>> iterable = side_effect(c.add, iterable)
    >>> consume(iterable)
    >>> sorted(c)
    [0, 1, 2]