Stefan Monnier writes: >> +The return value of said lambdas should be either >> + >> +- a valid let-binding (SYMBOL function) to be used in let* >> + bindings over BODY so that SYMBOL could be used in place of the >> + corresponding function name in BODY >> + >> +or >> + >> +- a list (NIL EXPR) for EXPR to be used in BODY in place of the >> + corresponding function name as is. > > Can we simplify this so only one of the two is supported? There are several ways to simplify this. Here they go, in the order of attractiveness (to you, as I perceive it): a. When flet-expander returns a symbol, plug it in as is. If it returns anything else, use it as initial value in a let binding. This basically mimics the present mechanism. It sounds good but the question is, why are we certain that we'll only ever want to plug in symbols. Plugging in symbols and symbols only is arbitrary, as my example with symbol-macrolet demonstrates. Aren't values of type “compiled-function” worth injecting directly as well? Arguably more so since at least they won't evaluate indefinite number of times with possible side effects. Same applies to other constant values that include present or future funcallable objects. What if expander returns nil or t? We probably should add exception concerning those. Overall, such spec involves guessing and eventually will get more complicated than what we started with. Which is why I don't recommend a. b. Allow building more let bindings than necessary As long as we have to distinguish between buliding a let binding and plugging in an external form as is, our lambda must return values of two distinguishable types. We might however unconditionally generate let bindings and use return values of flet-expanders as corresponding initial values. As was the case with “a”, the values don't have to specify gensyms then, and can be used directly instead. Note however that this would introduce incompatibility with the existing code due to presence of (func exp) syntax in cl-flet: it might be that some code that used to evaluate several times at runtime will only evaluate once. I understand that this is deemed unlikely (and I wish this logic could be applied to make consp return its argument for true --- even though this would not be not CL-compatible). Good news is, this would also make cl-flet with (func exp) more predictable. So far low-level functions of Emacs that generate Elisp code do try to avoid building more let bindings than necessary. In fact, cl-flet itself does this right now. IIUC, with native compiler in action, we might not care that much about minimizing let bindings. However, cleaner code generation helps with debugging, and not only debugging macros. My impression is, lispers generaly don't produce cleaner macroexpanded code because it would take too much time to write a procedure that does and because they don't see that much value in clean macroexpansions. I think they are valuable enough (which is why I took the time to ensure it in the case as important as cl-flet). Also, despite the fact that clean macroexpansions are not fashionable, complaints about difficulty of debugging macros themselves or of macroexpanded code, are fairly popular. Cluttered macroexpansions contribute to that difficulty. So I don't recommend b either. c. Transfer the relevant information from return type of code-generating lambdas into arguments' types of expand-flet c.1 We could introduce another argument that explicitly lists the symbols for which forms returned by flet-expanders are plugged in and no let bindings are generated. c.2 The expanders could be specified as either lambdas, in which case the return value is used in the flet body as is, or, say, singleton vectors [lambda] in which case the return value of funcall of the 0th element is used as let-binding. Downsides: (c.2.1) it might be worth it to make this decision late rather than early; (c.2.2) the interface gets more complicated and less reasonable. In c.2 I picked vector because it makes it less likely to confuse lambda expressions with something that should not be evaluated but overall I think complicating expand-flet is a bad idea anyway. So I don't recommend c as well. The proposed return value types, (var value) and (nil value), looked more straightforward to me than alternatives I could think of.