Indeed, FUNC would have to create a new environment for its arguments and locals. I don’t see any other way to implement it.
But FUNC is still needed. The key realisation here is: if we avoid doing any deep traversal, functions can only overbind values in the single block they’re passed. (And any unbound blocks nested within that.) They can’t overbind values in any nested bound blocks. So, if we want to ‘punch holes’ in those deeper blocks, we need to say so explicitly, using FUNC or an equivalent.
The result is a style of code where you have to explicitly specify whenever you want a block to receive overbinding. You can pass the outer block to FOR-EACH, but that does nothing to the inner block. So you need to explicitly overbind that block too.