A "smart" environment would have parallel functions for creating lexical bindings (and mechanisms) for values and functions. But the current environment is incapable of working that way. So, here's the kludge (well, it only becomes a kludge if it works, otherwise it's a crock). Example:
(let ((x 42))
...
(labels ((foo (a b) (foo (/ (+ a b) x) nil))
(bar (x) (* (foo x 13))))
(foo 1 2))
...)
I can't just turn it into a named function by changing the symbol-function slot of foo. Even if I had a mechanism to replace the original function foo, that would be a dynamic binding of foo's function slot. The CL spec requires that the binding is lexical. Making a "real" binding would be very difficult at this point. But I can use a trick from lambda calculus: renaming. I change the form into:
(let ((x 42))
...
(labels ((labels_foo_2883486 (a b)
(labels_foo_2883486 (/ (+ a b) x) nil))
(labels_bar_47927743 (x) (labels_foo_2883486 x 13)))
(labels_foo_2883486 1 2))
...)
The compiler runs through all of the uses of foo and substitutes them with the symbol labels_foo_2883486 d. This is risky because I might miss one. But it's a risk I'll take for now. Note that both foo and bar were renamed, as were all other their uses.
Having renamed all the uses of foo and bar, the compiler is free to treat the renamed foo and bar as top-level functions. Note in both cases, the variable x is lexically visible and correctly used.
Here's what the renamed version of foo and bar if they were built in the scope of an FLET.
(let ((x 42))
...
(flet ((flet_foo_2883486 (a b) (foo (/ (+ a b) x) nil))
(flets_bar_47927743 (x) (foo x 13)))
(flet_foo_2883486 1 2))
..
Note that the scoping in FLET differs from LABELS.
This kludge works at least in these examples. Nested FLET and LABELS would be problematic.