On Fri, Mar 17, 2023, at 3:54 AM, Michał Marcin Brzuchalski wrote:

>> As a thought experiment, if we had that syntax and functions that were
>> designed to be used with them, it would look like so:
>>
>> function amap(callable $c, iterable $it) { ... }
>> function implode(string $sep, iterable $it) { ... }
>> function length(string $s) { ... }
>>
>> $arr = [1, 2, 3];
>>
>> $a2 = amap(...)->partial(chr(...))($arr);
>>
>> $str = implode(...)->partial(',')($a2);
>>
>> Or, if combined with pipes:
>>
>> $size = $arr
>> |> amap(...)->partial(chr(...))
>> |> implode(...)->partial(',')
>> |> length(...);
>>
>> Which... is not terrible, especially as it doesn't preclude using higher
>> order functions for more control.
>>
>
> Maybe we could introduce two additional methods on a Closure similar to
> what Java have
> https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html
> * andThen() - which functionality is like a pipe operator
> * apply() - which you can call without the option to bind/rebind and just
> pass arguments for execution
>
> The pipe operator can be introduced later, but we could already have the
> functionality on Closure.
>
> The above example might look readable as well:
>
> $size = amap(...)->partial(chr(...))
>     ->andThen(implode(...)->partial(','))
>     ->andThen(length(...))
>     ->apply($arr);

See that brings up a subtle difference between two operations: pipe and compose.

Compose takes two functions A and B and returns a new function that is 
logically identical to B(A()).  (Or sometimes A(B()), depending on the 
language, which is all kinds of confusing.)

Pipe takes an arbitrary value and unary function and calls the function with 
that value immediately, returning the result.

You can build a pipe equivalent out of compose, although it's a bit clunky and 
the semantics are not *quite* identical.  (The order of execution is different, 
which may or may not matter depending on the specifics of each call.)

In the example above, andThen() is acting as a compose operator, while apply() 
is just boring function application.  It works but it's a bit clunky compared 
to a proper pipe.  That said, there are user space libraries that do that.

Thinking aloud...  I said before it would be better to have a native operator 
for all of these.  (compose, pipe, and partial.)  If we restrict ourselves to 
Closure objects rather than all callables (since callables are a lot messier), 
that does open up some new options.  Specifically, the following are already 
syntax errors today:

$c = strlen(...);
$d = array_map(...);

$c + $d; // not allowed.
$c . $d; // not allowed, thinks it's string concat and $c isn't stringable.
$c[2, 3]; // not allowed.
$c{5}; // not allowed, thinks it's a string offset.

So that suggests to me the following:

* Define $a + $b on closure objects to be a compose operator that returns a new 
function equivalent to $b($a( )).  It would only work on unary functions, 
validate compatible types between the param and return values, and have the 
correct type information.

* Define $c{ ... } as a "partial application" call.  The {} body would be 
similar to a function call now; or maybe the original PFA syntax with ? and ... 
?  Debatable, but the {} would be a better signal to the engine that we're not 
calling a function, just partially calling.  It's also reasonably self-evident 
to developers.

Those two together would allow for this:

(amap{chr(...), ?} + implode{?, separator: ','} + length(...))($arr);

Which is... pretty nice, really.  It's very close to the original PFA syntax 
and capabilities, compact, not easily confused with anything else, type safe, 
and the engine can handle optimizing around not having unnecessary interstitial 
functions internally.

I still think we should also add a pipe operator |> as well, but that would be 
just as compatible with the {}-based PFA syntax.  It's also fairly trivial to 
implement.

$size = $arr
  |> amap{chr(...), ?)
  |> implode(',', ?)
  |> length(...);

Thoughts?

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to