I'm looking for (real world) uses of fexprs, where they are used in a way different to what can be accomplished with lazy evaluation.
Most examples that I could find use fexprs only to implement conditional evaluation, like for a short circuit "and" operative (Evaluate first argument, if false, don't evaluate second and directly return false).
I'm looking for "useful" uses, that is where using fexpr leads to code that is "better" (cleaner) than what could be done without fexprs.
There are two main reasons you would want to use fexprs.
The first one is because they allow you to evaluate the arguments an arbitrary number of times. This makes it possible to implement operators that evaluate their arguments lazily like you suggested. Constructs built this way are also capable of evaluating their arguments more than once. This makes it possible to implement loops through fexprs!
The other case is for transformation. Transforming code is basically a way of writing a compiler on top of your existing Lisp. Although it uses macros and not fexprs, cl-who is a great example of the kind of transformations that can be made.
Fexpr are somewhat orthogonal to lazy/eager evaluation.
The usual function approach is to eval the arguments to a function then call it on the result. Lazy eval still behaves like this, it just delays the evaluation until immediately before the parameter is used.
The usual macro approach is to pass the unevaluated arguments into a template which evaluates anything that isn't quoted. The resulting piece of AST is injected into the call site where it is usually evaluated again. This works much the same with lazy eval.
The historically insane fexpr approach is to pass unevaluated arguments to the function, which does as it pleases with them. The result is injected directly into the call site and usually not evaluated automatically.
The fexpr is pretty close to an arbitrary transform. So you can implement macros and lambdas with them. You can also implement whatever hybrid of eager/lazy evaluation you wish. Likewise you could implement fexpr given default lazy eval and explicit calls to eval() in various places to force eager behaviour.
I don't think I would characterise fexpr as an easy solution to implementing lazy eval though, in a cure is worse than the disease sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With