Thanks for linking to Fexpr's. I've thinking about "functions with lazily evaluated arguments" recently, and trying to understand how they are different from macros. So I was basically thinking about fexprs.
I have some reading to do, but overall it seems like macros are favored instead of fexprs. Macros completely avoid some environment handling issues.
The only language with Fexprs that I used was Io. In Io, unevaluated code is represented as a tree of Message nodes, and for each call, an activation record is instantiated and provided to the called method body. That reified Call object lets you access the caller's environment and the raw Message chains passed as arguments. You can then decide whether to evaluate those messages, which ones, how many times, and in what context/environment. It's a very niche language, but if you want to see Fexprs "in action", that's the best place to look at (at least to my knowledge) - they are central to Io's design rather than an advanced feature nobody touches. It's even mentioned on the front page[1]:
> Messages as Code — Messages form trees that can be inspected and rewritten at runtime. Argument evaluation can be deferred, so if, while, and for are implementable in Io itself.
[1] https://iolanguage.org/