On 25/04/2021 20:25, Larry Garfield wrote:
Greetings, Internalians!
I would like to offer for your consideration another RFC, specifically syntax
for partial function application.
https://wiki.php.net/rfc/partial_function_application
During off-list discussions, it's become clear that there are two
different ways of modelling what this feature does, which is leading to
a bit of misunderstanding and frustration (and some plain disagreement
on which is the *better* model). At risk of getting it wrong and
confusing things more, I'd like to attempt to describe the two models.
The first model is that a partial application starts with an empty
signature, and adds arguments to it based on placeholders. You could
picture the steps like this:
function foo(int $a, int $b, int $c) { /* whatever */ }
$partial = foo(?, ?, 42);
Step 1 - empty closure: $partial = fn() => foo();
Step 2 - 1st argument is a ? so copy that parameter from the original:
$partial = fn(int $a) => foo($a);
Step 3 - 2nd argument is a ? so copy from the original: $partial =
fn(int $a, int $b) => foo($a, $b);
Step 4 - 3rd argument is a fixed value, so don't add to signature, only
to the call: fn(int $a, int $b) => foo($a, $b, 42);
The second model is that a partial application starts with a *complete*
signature, and splices in the *fixed* values. The steps go more like this:
function foo(int $a, int $b, int $c) { /* whatever */ }
$partial = foo(?, ?, 42);
Step 1 - copy original signature: $partial = fn(int $a, int $b, int $c)
=> foo($a, $b, $c);
Step 2 - 1st argument is a ? so skip over it
Step 3 - 2nd argument is a ? so skip over it
Step 4 - 3rd argument is a fixed value, so splice a value into the
signature at that location: $partial = fn(int $a, int $b, 42) => foo($a,
$b, 42);
Step 5 - fixed values don't actually belong on the left-hand side:
$partial = fn(int $a, int $b) => foo($a, $b, 42);
For simple examples like the above, the two models are essentially
equivalent, but they lead to different expectations for some features;
for instance, trailing arguments and placeholders:
- In the model where you're building from empty, writing foo(42, ?, ?)
to mean "copy exactly two arguments" feels natural. To say "copy all
arguments", or "copy all remaining arguments", you'd then need a
different syntax, like foo(42, ...) or foo(42, ??). In this model, the
trailing "?" in the current proposal is magic: it changes from meaning
"copy exactly one argument" to "copy all remaining arguments".
- In the model where you're splicing arguments into a full signature,
foo(42, ?, ?) is pointless: the action is to splice in the 42, then
"skip over" two arguments; but nothing happens *after* skipping over
them, so you could just not mention them. No extra token is needed to
copy all remaining arguments, because that already happened at the
start. The only reason to use a trailing "?" at all is because foo(42)
would just be a normal function call, and adding a redundant "skip over"
marker in foo(42, ?) tells the compiler it's a partial.
Regards,
--
Rowan Tommins
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php