def var(name, index=None):
    tname = type(name)
    if tname is str:
        names = (name, )
    elif tname is tuple:
        names = name
    else:
        fstr = "expected name to be a str or tuple, got {0.__name__}"
        raise TypeError(fstr.format(tname))
    if not names:
        raise ValueError("expected at least one name")
    for name in names:
        tname = type(name)
        if tname is not str:
            fstr = "expected name to be a str, got {0.__name__}"
            raise TypeError(fstr.format(tname))
    if index is None:
        indices = tuple()
    else:
        tindex = type(index)
        if tindex is int:
            indices = (index, )
        elif tindex is tuple:
            indices = index
        else:
            fstr = "expected index to be an int or tuple, got {0.__name__}"
            raise TypeError(fstr.format(tindex))
    for index in indices:
        tindex = type(index)
        if tindex is not int:
            fstr = "expected index to be an int, got {0.__name__}"
            raise TypeError(fstr.format(tindex))
        if index < 0:
            fstr = "expected index to be >= 0, got {}"
            raise ValueError(fstr.format(index))
    try:
        v = VARIABLES[(names, indices)]
    except KeyError:
        v = Variable(names, indices)
        VARIABLES[(names, indices)] = v
    return v