We seek a function ba such that ba returns strings. Specific examples of the desired behavior of ba are shown below:
+------------------+--------+
|      INPUT       |  OUT   |
+------------------+--------+
| 0                | "0"    |
| [[0, 1], 2, 3]   | "0123" |
| [0, 1, 2, 3]     | "0123" |
| [0, [1, [2, 3]]] | "0123" |
+------------------+--------+
Consider the following function:
def a(x):
    if hasattr(x, '__iter__'):
        return map(a, x)
    return x
EDIT!
Note that the following is an infinite loop:
it = "python"
while hasattr(it, '__iter__'):
    it = iter(it)
This is because "p"[0][0][0][0][0][0][0]...[0] == "p"
Thus, we really want something like:
def a(xparent):
    try:
        r = xparent
        if hasattr(xx, '__iter__'):
            iparent = iter(xparent)
            if iparent != xparent:
                r = map(a, xparent)
    finally:
        return r
Assume that you're not allowed to change a very much. If ba == lambda x: b(a(x)), the questions is, what would work for function b?
The following candidates don't work:
b = lambda x: ''.join(map(str, x))
b = lambda x: str(map(str, x))
Below is some code I created for testing/debugging potential candidates for function b:
#     YOU CAN IGNORE MOST OF THE BEGINNING OF THE FOLLOWING SCRIPT
#                              _  _       _
#                             | || |     | |
#      ___   ___  _ __   ___  | || |   __| |  ___  __      __ _ __
#     / __| / __|| '__| / _ \ | || |  / _` | / _ \ \ \ /\ / /| '_ \
#     \__ \| (__ | |   | (_) || || | | (_| || (_) | \ V  V / | | | |
#     |___/ \___||_|    \___/ |_||_|  \__,_| \___/   \_/\_/  |_| |_|
#
#
#
if True:
    # `stderr` is printed out-of-order with `stdout`.
    #
    # I'm tired of exceptions printed to `stderr`
    # messing up the print statements
    #
    import sys
    _print  = lambda *args, file=sys.stderr, end="\n",:\
        file.write(' '.join(map(lambda arg: str(arg).strip(" "), args)) + end)
    print = _print
##############################################################
import inspect
import io
def e(mahp):
    out_frm = inspect.currentframe().f_back
    try:
        outout = eval(mahp, out_frm.f_globals, out_frm.f_locals)
    except BaseException as exc:
        with io.StringIO() as out:
            print(type(exc), exc, file=out)
            outout = out.getvalue()
    finally:
        try:
            return outout
        except UnboundLocalError:
            raise ValueError(''.join((x for x in (
                "except block failed to assighn to `outout`"
                "most likely "
            ))))
############################################################
#          _                                           _  _  _
#         | |                                         | || |(_)
#     ___ | |_   ___   _ __    ___   ___  _ __   ___  | || | _  _ __    __ _
#    / __|| __| / _ \ | '_ \  / __| / __|| '__| / _ \ | || || || '_ \  / _` |
#    \__ \| |_ | (_) || |_) | \__ \| (__ | |   | (_) || || || || | | || (_| |
#    |___/ \__| \___/ | .__/  |___/ \___||_|    \___/ |_||_||_||_| |_| \__, |
#                     | |                                               __/ |
#                     |_|                                              |___/
import copy
# def a(xparent):
#    try:
#        r = xparent
#        if hasattr(xparent, '__iter__'):
#            iparent = iter(xparent)
#            if iparent != xparent:
#                r = map(a, xparent)
#    finally:
#        pass
#    return r
def a(x):
    if hasattr(x, '__iter__'):
        return map(a, x)
    return x
Lneg = "01234"
L0 = 0
L1 = [[0, 1], 2, 3]
L2 = [0, 1, 2, 3]
L3 = [0, [1, [2, 3]]]
Ls = [Lneg, L0, L1, L2, L3]
def observe_one(candidate):
    candidate = str(candidate)
    print(candidate, end="\n    ")
    print(e(candidate))
    return
def observe_all(mahp):
    if True:
        # `mahp` is an iterator. As such, it will be empty once
        # traversed. Use `deepcopy` to test `mahp` multiple times
        print(30*"#")
        print("L == ", end="\n    ")
        print(L)
        print()
        observe_one("''.join(map(str, copy.deepcopy(mahp)")
        print()
        observe_one("str(map(str, copy.deepcopy(mahp)))")
        print(30 * "#")
for L in Ls:
    try:
        mahp = a(L)
        observe_all(mahp)
    finally:
        pass
 
    