import six


def merge(*dictionaries):
    """Recursively merge one or more dictionaries together.

    Conflict resolution:
        - Dictionary values are recursively merged.
        - List values are added together.
        - Sets are combined with `__or__` (equivalent of set.union).
        - Everything else, the right-most value wins.
        - If values are type mismatches in the above resolution rules,
          raise ValueError.

    Args:
        *dictionaries (list(dict)): Dictionaries to be merged.

    Returns:
        dict: The merged dictionary.
    """
    answer = {}
    for d in dictionaries:
        for k, v in six.iteritems(d):
            # If the value is not yet found in the answer, then
            # simply add it and move on.
            if k not in answer:
                answer[k] = v
                continue

            # If the values are both lists, append them to one another.
            if isinstance(answer[k], list):
                if not isinstance(v, list):
                    raise ValueError('Attempt to merge a list and non-list.')
                answer[k] = answer[k] + v
                continue

            # If the values are both sets, take their union.
            if isinstance(answer[k], set):
                if not isinstance(v, set):
                    raise ValueError('Attempt to merge a set and non-set.')
                answer[k] = answer[k] | (v)
                continue

            # If the values are both dictionaries, merge them recursively
            # by calling this method.
            if isinstance(answer[k], dict):
                if not isinstance(v, dict):
                    raise ValueError('Attempt to merge a dict and non-dict.')
                answer[k] = merge(answer[k], v)
                continue

            # These are either primitives or other objects; the right-hand
            # value wins.
            answer[k] = v
    return answer