I would forget about package-level “partial”. That’s too much for the most basic syntax. In fact what I outline below already feels somewhat overwhelming. The package-level stuff could be utilities built on top of what we discuss here but they would not be an (indispensable) part of it.
How about using `
?
One could transform (at AST post-processing stage) `rhs(a1, a2, ~, a3, k1=1, k2=~, k3=3)
into a variant of lambda
(only at AST level - for combining with |>
later; post-optimization, only regular lambas would be passed to the compiler for bytecode production):
pipelambda lhs, in_pipeline=False: \
(
rhs(a1, a2, lhs, a3, k1=1, k2=lhs, k3=3)
if not in_pipeline
else (
lhs.__lcall__(rhs, a1, lhs, a3, k1=1, k2=lhs, k3=3)
if hasattr(lhs, "__lcall__")
else (
rhs.__rcall__(lhs, rhs, a1, lhs, a3, k1=1, k2=lhs, k3=3)
if hasattr(rhs, "__rcall__")
else rhs(a1, lhs, a3, k1=1, k2=lhs, k3=3)
)
)
)
The method invocation could use double `
, i.e. ``
. It would be simply ``method_name
or ``method_name(...)
. It would translate to:
lambda lhs, in_pipeline=False: \
(
getattr(rhs, method_name)(a1, a2, lhs, a3, k1=1, k2=lhs, k3=3)
if not in_pipeline
else (
lhs.__lcall__(getattr(rhs, method_name), a1, lhs, a3, k1=1, k2=lhs, k3=3)
if hasattr(lhs, "__lcall__")
else (
rhs.__rcall__(lhs, getattr(rhs, method_name), a1, lhs, a3, k1=1, k2=lhs, k3=3)
if hasattr(rhs, "__rcall__")
else getattr(rhs, method_name)(a1, lhs, a3, k1=1, k2=lhs, k3=3)
)
)
)
My fancy example could now be written:
`pd.read_csv(...) |> ``query("A > B") |> `filter(items=["A"]) |> ``to_numpy |> ``flatten |> ``tolist |> `map(lambda x: x + 2) |> list |> np.array |> ``prod
|>
could be made to accept raw callables (i.e. list
instead of `list
) or not. I think it’s fine to accept them and just transform raw callables into pipelambda
when part of a pipeline. All could happen during AST post-processing.
Heavy but not too bad and this could satisfy everything we talked about, no? Split into components (new “partial” and the |>
operator) and magic methods (__lcall__
, __rcall__
) for extensibility, terse syntax for syntactic convenience
Four new tokens `
, ``
, ~
and |>
but a nice syntax without unexpected behaviors and not that much of a cognitive load IMHO.
What do you think?
PS. Better alternatives for backtick could be !
or \
(if we allowed it mid-line and made it mean line continuation only when actually used at line end).
!pd.read_csv(...) |> !!query("A > B") |> !filter(items=["A"]) |> !!to_numpy |> !!flatten |> !!tolist |> !map(lambda x: x + 2) |> list |> np.array |> !!prod
\pd.read_csv(...) |> \\query("A > B") |> \filter(items=["A"]) |> \\to_numpy |> \\flatten |> \\tolist |> \map(lambda x: x + 2) |> list |> np.array |> \\prod
Actually, I like !
/ !!
quite a lot - they naturally bring a lot of attention where attention is due.