docs: def to_string(interval, conv=repr, disj=' | ', sep=',', left_open='(',
                left_closed='[', right_open=')', right_closed=']', pinf='+inf', ninf='-inf'):
      """
      Export given interval (or atomic interval) to string.
  
      :param interval: an Interval or AtomicInterval instance.
      :param conv: function that is used to represent a bound (default is `repr`).
      :param disj: string representing disjunctive operator (default is ' | ').
      :param sep: string representing bound separator (default is ',').
      :param left_open: string representing left open boundary (default is '(').
      :param left_closed: string representing left closed boundary (default is '[').
      :param right_open: string representing right open boundary (default is ')').
      :param right_closed: string representing right closed boundary (default is ']').
      :param pinf: string representing a positive infinity (default is '+inf').
      :param ninf: string representing a negative infinity (default is '-inf').
      :return: a string representation for given interval.
      """
      interval = Interval(interval) if isinstance(interval, AtomicInterval) else interval
  
      if interval.is_empty():
          return '{}{}'.format(left_open, right_open)
  
      def _convert(bound):
          if bound == inf:
              return pinf
          elif bound == -inf:
              return ninf
          else:
              return conv(bound)
  
      exported_intervals = []
      for item in interval:
          left = left_open if item.left == OPEN else left_closed
          right = right_open if item.right == OPEN else right_closed
  
          lower = _convert(item.lower)
          upper = _convert(item.upper)
  
          if item.lower == item.upper:
              exported_intervals.append('{}{}{}'.format(left, lower, right))
          else:
              exported_intervals.append('{}{}{}{}{}'.format(left, lower, sep, upper, right))
  
      return disj.join(exported_intervals)