Re: pipes, scalar objects and on?
| From: | Larry Garfield | Date: | Tue, 18 Jul 2023 18:08:08 +0000 |
| Subject: | Re: pipes, scalar objects and on? | ||
| References: | 1 2 3 4 5 6 7 8 9 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-120844@lists.php.net to get a copy of this message | ||
On Tue, Jul 18, 2023, at 5:08 PM, Karoly Negyesi wrote:
> My favorite pipeline is Elixir, where "The pipe operator |> passes the
> result of an expression as the first parameter of another expression".. But
> it works there because unlike with PHP, it's almost always the first
> argument you want. If it's not the first argument you needed to do some
> tricks which was only cleaned up in 2021 so now they do:
>
> 5
> |> then(&Enum.take(1..10, &1))
> |> Enum.reverse()
>
> but I digress.
>
> My problem here is... we actually need something that passes the RFC vote.
>
> What flexibility is missing here?
Please don't top post.
The main flexibility for callables is the ability to build a closure on the fly. For example, using
$$ (which Hack does, and I insist on calling T_BLING) means that for array and string functions you
still need to worry about parameter order. With a callable, you can effectively emulate
Elixir's behavior if you want.
For example, my FP library has a whole bunch of higher order functions that just return pipe-ready
functions:
https://github.com/Crell/fp/blob/master/src/array.php
Which, with a pipe operator, would allow for:
$result = $arr
|> amap(trim(...))
|> afilter(is_int(...))
|> reduce(0, $fn)
|> trim(...) // At this point it's a string and trim() is already unary, so we can just
use it.
;
Which is pretty nice, IMO. It "flows" nicely, supports both higher order functions and
direct calls equally well, and allows for all kinds of further expansion that I haven't thought
of yet.
The Hack style would require thinking about the fact that array_map() and array_filter() take their
arguments in reverse order from each other, which is just silly. This way, that problem goes away
entirely.
It also allows a pipe to be used as a quasi alternative to scalar methods, because (if we set aside
visibility for the moment) a method is just a function with an implicit $this parameter. Callables
and higher order functions make that a lot cleaner.
The caveat is that it does add an extra step to use many of the existing array or string stdlib
functions. However, that's work that can be done once. The link above is under 500 lines,
heavily documented, and covers every array use case I've run into so far.
Related improvements:
* Writing a higher order function right now is rather cumbersome. There were two previous RFCs that
would have made that vastly nicer (short-functions and auto-capture closures), but neither passed.
They would have allowed for:
function amap(callable $c) => fn (iterable $it): array {
if (is_array($it)) {
return array_map($c, $it);
}
$result = [];
foreach ($it as $k => $v) {
$result[$k] = $c($v);
}
return $result;
};
Which I think is pretty nice.
* PFA would give us the best of both worlds, as if you wanted you could do:
$result = $arr
|> array_map(trim(...), ?)
|> array_filter(?, is_int(...))
|> array_reduce(?, $fn, 0)
|> trim(...)
;
So with PFA and callable pipes, we get both options. If pipe was just Hack-style, there would be no
way to use higher order functions with it.
So IMO, the ideal experience that gets almost everyone what they want would be if all four of the
following had passed:
https://wiki.php.net/rfc/short-functions
https://wiki.php.net/rfc/auto-capture-closure
https://wiki.php.net/rfc/partial_function_application
https://wiki.php.net/rfc/pipe-operator-v2
They are all mutually-complementary, but also useful on their own, and were designed that way
deliberately. Sadly, all four were declined.
So yeah, it's great that there's renewed interest in pipes, but I've already sunk a
ton of time into this space (as have many other people that helped with those RFCs) with nothing to
show for it. Unless there's indication from a notable number of voters that they'd
support it now, I'm reluctant to sink much more of my time (or anyone else's time) into
something that has so far just run into brick walls.
If any of the above has convinced someone that we should try any of these features again, please
speak up. I seriously do want this functionality, but OSS spec work is not my favorite way to spend
time.
--Larry Garfield