dbrattli / Expression

Functional programming for Python
https://expression.readthedocs.io
MIT License
497 stars 32 forks source link

Pipe joining #214

Open Hugovdberg opened 3 months ago

Hugovdberg commented 3 months ago

Is your feature request related to a problem? Please describe. Every once in a while I encounter a method that is not curried, which I would like to use in a expression.pipe, more often than not methods on pandas.DataFrame's. There currently is a way to curry the method inline:

res = expression.pipe(
    df,
    expression.curry_flip(1)(pd.DataFrame.merge)(df2)
)

However, all the parentheses become quite ugly and unreadable.

Describe the solution you'd like We can of course make this a little better with a helper function that does the curry_flip of the first argument:

join = expression.curry_flip(1)
res = expression.pipe(
    df,
    join(pd.DataFrame.merge)(df2)
)

This is a little better, but the double pair of parentheses still feels off. Therefore, I propose to include a function to do this natively:

_a = TypeVar("_a")
_b = TypeVar("_b")
_P = ParamSpec("_P")

def join(
    func: Callable[Concatenate[_a, _P], _b], *args: _P.args, **kwargs: _P.kwargs
) -> Callable[[_a], _b]:
    return expression.curry_flip(1)(func)(*args, **kwargs)

res = expression.pipe(
    df,
    join(pd.DataFrame.merge, df2)
)

Describe alternatives you've considered The name might be something to discuss, but conceptually join makes the most sense to me as you are joining segments in a pipeline. However, the generic name might make it a little confusing, so perhaps this should be made clear from the namespace.