paldepind / flyd

The minimalistic but powerful, modular, functional reactive programming library in JavaScript.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support multiple operators for Pipe

NoelAbrahams opened this issue · comments

Hi — brilliant library

Simple question: I would like to do the following:

mystream
    .pipe(
       flyd.filter(value => value !== 'foo'),
       flyd.skip(1),
       flyd.dropRepeats()
    )
    .map((value) => {
        console.log(value);
    });

Instead of

mystream
    .pipe(flyd.filter(value => value !== 'foo'))
    .pipe(flyd.skip(1))
    .pipe(flyd.dropRepeats())
    .map((value) => {
        console.log(value);
    });

Basically to avoid repeating .pipe as it is much cleaner.

I've seen some discussion here: #137

I'm assuming this pattern for pipe is somehow contrary to the design of flyd?

Thanks

I'm assuming this pattern for pipe is somehow contrary to the design of flyd?

IIRC the reason we went for a single function passed to pipe was because we didn't want to introduce the complicated TS required to type such a pipe function.

Ultimately pipe is a pretty generic thing, have you considered using something like remeda's pipe?

R.pipe(
    mystream,
    flyd.filter(value => value !== 'foo'),
    flyd.skip(1),
    flyd.dropRepeats(),
    flyd.map(console.log)
)

It will be nice to have this supported by the flyd lib. I've had a look at the API of a bunch of other similar libraries but I really like the fact that you have gone with pipe (which many other's don't seem to have).

There's nothing terribly wrong with chaining multiple pipe calls, but in the land of FRP these small deviations can grate, something explained quite well in this article on FRP.

Happy to help with the TS bits if needed.

I would hesitate to change it if it's only for stylistic preference. As mentioned, pipe is a pretty generic function that you can easily implement outside any library and can then use with any of your types.

const pipe = (x, f, ...fs) => fs.reduce((x, f) => f(x), f(x))

I've added the following to the lib locally:

Code

    function operator_pipe(...fns) {
        return fns.reduce((x, f) => f(x), this); 
    }

Typing

pipe<R>(op: OperatorFunction<T, R>): Stream<R>;
pipe<A1, V>(op0: OperatorFunction<T, A1>, op1: OperatorFunction<A1, V>): Stream<V>;
pipe<A1, A2, V>(op0: OperatorFunction<T, A1>, op1: OperatorFunction<A1, A2>, op2: OperatorFunction<A2, V>): Stream<V>;
pipe<A1, A2, A3, V>(
    op0: OperatorFunction<T, A1>,
    op1: OperatorFunction<A1, A2>,
    op2: OperatorFunction<A2, A3>,
    op3: OperatorFunction<A3, V>,
): Stream<V>;
pipe<A1, A2, A3, A4, V>(
    op0: OperatorFunction<T, A1>,
    op1: OperatorFunction<A1, A2>,
    op2: OperatorFunction<A2, A3>,
    op3: OperatorFunction<A3, A4>,
    op4: OperatorFunction<A4, V>,
): Stream<V>;

Where

    interface UnaryFunction<T, R> {
        (source: T): R;
    }
    interface OperatorFunction<T, R> extends UnaryFunction<Stream<T>, Stream<R>> {}

This works for me. Happy to close the issue if it's not going to be supported.