Looking at this question 7 years later...I think we're not going to get too much better than functions for the "prepared statement handle", in terms of "parameterized thing you can execute".
rebElide("f: function[a] [return a * 2]");
Value* printer = rebValue("lambda [a label] [print [(f a) label]]");
rebElide(printer, 5, "-{apples}-");
The good news is that you should be able to use innovations like POINTFREE (or whatever it's called), or any other in-language conveniences to define these functions.
rebElide("f: function[a] [return a * 2]");
Value* printer = rebValue("pointfree [print [(f _) _]]"); // single scan
rebElide(printer, 5, "-{apples}-"); // not scanning POINTFREE/PRINT
rebElide(printer, 10, "-{bananas}-"); // not scanning POINTFREE/PRINT
rebElide(printer, 15, "-{kiwis}-"); // not scanning POINTFREE/PRINT
It's not completely known how that will work, but this is pretty much what's on the table for "prepared statements"...just various convenient usermode function generators.
Convenience Entry Points Possible...
I've mentioned the idea of making macros to make these calls briefer.
#define rebPointfree(...) rebValue("pointfree [", __VA_ARGS__, "]")
rebPointfree("print [(f _) _]")
So that should be able to syntactically match the brevity of @IngoHohmann 's rebPrepare()