Folding function invocations into arguments on-the-fly


#1

This idea emerged first in Rebmu, and is rather interesting. The idea is that if a function has an argument intended to be used at least once (like a BLOCK! condition of a WHILE), and that argument starts with a WORD! or PATH! that looks up to an ACTION!..that its arguments be evaluated in one swoop, but captured into a specialized function.

So imagine if WHILE were changed such that:

while [all [a b c]] [code]

Could be written equivalently as:

while all [a b c] [code]

The machinery to do this is weird, but a fledgling implementation does exist. It’s the kind of thing used to implement a similar trick in DOES, e.g. z: does collect [keep x keep y].

To get it to work with something like this WHILE case, it has to become variadic. Then it has to peek at its first argument, see that it is not a BLOCK! and that it looks up to an ACTION!. Then it requests to create a fully-specialized version of that function based on the invocation, and treats that function as the argument.

Obviously this would break cases where you wanted the function to be called in order to supply the condition itself, e.g.

while any [if foo [[x < 10]] else [[x > 20]]] [code]

Ordinary WHILE of today would run that ANY just once, get the BLOCK! to use as a condition, and then use that block on each iteration. But one way of getting past this would be to use a GROUP!, thus suppressing the automatic specialization of the ANY:

while (any [if foo [[x < 10]] else [[x > 20]]]) [code]

Another major weakness is that it captures its arguments just once. So using the trick with a loop like WHILE doesn’t do what you’d think:

while even? x [...]

It builds a call to even? using the value of x at the time it specializes it. Then every subsequent call after that to the constructed function will use that value.

So not great for looping, but still a useful mechanism

Being able to create a specialization just from seeing a call is a powerful ability, which hasn’t quite found the right shape to expose to userspace yet. I was thinking specialization might be what you get when you MAKE ACTION! from a GROUP!, e.g.

>> ph: make action! (print "Hello")
>> ph
Hello

Partial specialization is also a possibility:

>> block: copy [a b c] 
>> apb: make action! (append block)
>> apb <foo>
== [a b c <foo>]

I also have toyed with the idea that BLANK! (or void?) might be used to skip over spots:

>> block: copy [a b c]
>> apf: make action! (append _ <foo>)
>> apf block
== [a b c <foo>]

But in cases like building the weird WHILE above, what would need to happen is that a function would have to be able to generate a specialization on the fly from a VARARGS!.

I’m not sure exactly when this mechanism is appropriate to use outside of code golf. DOES seems pretty harmless so far. But turning the in-the-box WHILE into a quoting variadic to save a couple of brackets would likely be a bad idea.

Either way, it’s worth having in the toolbox, and good to stress the system a bit.


#2

Is this an optimization that is going to be used to compile ren-c code?


#3

It’s purely an attempt to try and cut down the number of characters used in source.

The techniques used to do it add processing…though if done correctly, it shouldn’t add very much processing.

It’s done in a fairly circuitious way at the moment, but things tend to improve a lot over their first cut implementations with time.