dissoc(m, k1, k2...) yields a map equivalent to m without the arguments k1, k2, etc. If m is a
      mutable pythin dictionary, this is equivalent to using del m[k] for k in [k1, k2...] then
      returning m itself. If m is a persistent map, this is equivalent to calling m = m.discard(k)
      for all the keys then returning m.

    If m is not a map but is instead a list or persistent vector, this operates as if the
    list/vector is a map whose keys are integers. If an item not at the end of the vector is deleted
    then it is replaced with None instead of pop'ed.

    The optional argument error (default: False) specifies whether an error should be raised when
    one of the keys is not found; this applies to mutable or immutable arguments.

def dissoc(m, *args, **kw):
    '''
    dissoc(m, k1, k2...) yields a map equivalent to m without the arguments k1, k2, etc. If m is a
      mutable pythin dictionary, this is equivalent to using del m[k] for k in [k1, k2...] then
      returning m itself. If m is a persistent map, this is equivalent to calling m = m.discard(k)
      for all the keys then returning m.

    If m is not a map but is instead a list or persistent vector, this operates as if the
    list/vector is a map whose keys are integers. If an item not at the end of the vector is deleted
    then it is replaced with None instead of pop'ed.

    The optional argument error (default: False) specifies whether an error should be raised when
    one of the keys is not found; this applies to mutable or immutable arguments.
    '''
    if   len(kw) == 0: err = False
    elif len(kw) == 1: err = kw['error']
    else:              raise ValueError('unrecognized optional arguments')
    if is_pmap(m):
        if err:
            for k in args: m = m.remove(k)
        else:
            for k in args: m = m.discard(k)
        return m
    elif is_map(m):
        if err:
            for k in args: del m[k]
        else:
            for k in args:
                if k in m: del m[k]
        return m
    elif isinstance(m, tuple_type):
        return m if len(args) == 0 else tuple(dissoc(list(m), *args, error=err))
    elif isinstance(m, list_type):
        if len(args) == 0: return m
        n = len(m)
        if err:
            for k in args:
                if not is_int(k) or k < 0 or k >= n: raise KeyError(k)
        else: args = [k for k in args if is_int(k)]
        args = sorted(list(set(k if k >= 0 else n + k for k in args)))
        if err:
            for k in args:
                if k < 0 or k >= n: raise KeyError(k)
        else: args = [k for k in args if k < n and k >= 0]
        n -= 1 # just for eliminating the == n-1 in the next line
        while len(args) > 0 and args[-1] == n:
            m.pop()
            args.pop()
            n -= 1
        for k in args: m[k] = None
        return m
    elif is_nparray(m):
        args = list(args)
        if len(args) == 0: return m
        return np.asarray(dissoc(m.tolist(), *args, error=err))
    else: raise ValueError('Cannot dissoc from given type: %s' % type(m))