-
-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does xstream have a similar concept to rx's pipeable operators? #243
Comments
Not built in, but it wouldn't be hard to make a package like so: const map = (...args) => (stream) => stream.map(...args);
const filter = (...args) => (stream) => stream.filter(...args);
const pipe = (stream, ...operators) => operators.reduce((s, f) => f(s), stream);
const result = pipe(
xs.fromArray([1, 2, 3]),
map(i => i * 2),
filter(i => i > 3)
) If you wanted to match the rx api exactly you would do this: xs.prototype.pipe = function (...operators) { return operators.reduce((s, f) => f(s), this) }; I'm sure there are quite a few people who would appreciate someone making an I don't think it will ever end up in the core xstream library since it's not strictly necessary and having a small bundle is a goal for xstream. |
Thanks for the code Nick! I like your way better than the rx api. Cleaner. Given that syntax, how would you think about creating custom operators? I started to create a function that returned a listener object, but then realized it would likely need a producer. Looking at the code (oooh. One file. Clean. Nice inline docs. Beautiful!), it looks like most of the operators return a combined listener+producer object. Hmm. They're intermittently polymorphic too. Thinking out loud here, maybe it would be simpler to create them using the existing operators. That should be easy enough since they can be piped/composed using your syntax. Something like: const pipe$ = (...operators)=>stream=>operators.reduce((s, f) => f(s), stream);
// ^^ same concept, with operators first for composability, followed by $ to distinguish it
// from a regular pipe function.
// wait... no.
// It IS a regular pipe function written that way.
// There's no need to write a custom pipe operator.
// Regular pipe/compose functions would work fine.
// so an omit function (opposite of filter) could just be written like:
const filter = predicate => stream => stream.filter(predicate);
const not = predicate=>(...args)=>!predicate(...args);
const omit = pipe(not, filter); // or compose(filter, not);
const takeNon3sUntil7 = pipe( omit(x=>x%3===0), take(5));
const non3sTo7$ = takeNon3sUntil7(xs.fromArray([1,2,3,4,5,6,7,8]));
// --1--2-----4--5-----7| Does that make sense? To summarize, more complex operators can be implemented as one-liners by applying regular pipe/compose functions to the existing set of operators (each written as |
That is indeed correct 😃 |
I did it here: https://github.com/anilanar/xstream-pipe |
@staltz Referring to your comment here, do you still consider replacing methods with pipeable operators in the core to minimize API surface? Current implementation is mixing methods with What do you think about dropping methods in favor of a single |
@raveclassic It's important for xstream to not have breaking changes unless it's unavoidable, because there are many codebases and tutorials that depend on xstream's API as it is right now. For a more modular approach, I recommend taking a look at https://github.com/callbag/callbag which is also a possible replacement for xstream inside Cycle.js in the future. |
@staltz Yeah I agree xstream should not break API. At least the methods could be deprecated in favor of |
https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
I'm a huge fan of FP with pipe and compose (ramda, lodash/fp), so I like that rx has a pipe fn. I also like xstream's simplicity. Curious if xstream enables piping of some sort, sans the dot. Fns like
.map
and.filter
make me a bit apprehensive. Patching prototypes for custom fns can get tricky, especially if the chaining hides internal mutation.Compose seems like it might be similar to
source$.pipe(fns...)
in the rx link. Is it? And, if so, how easy would it be to reverse it for pipe's redability? e.g.,const pipe = (...fns)=>compose(...fns.reverse());
.Related: This mention of pipe-style api seems like it might reference the same concept, but is the only issue with the word "pipe" in it.
Thanks!
The text was updated successfully, but these errors were encountered: