Closed boneskull closed 8 years ago
So you want something like the following?
var foos = ...some stream...
var bars = ...some stream...
var notBars = Kefir.difference(foos, bars)
Something like lodash's partition could do the job in a single statement.
let [bars, notBars] = foos.partition(v => v === "bar")
And we can improve on the concept by allowing more than one predicate function:
let [bars, foobars, rest] = foos.partition(
v => v === "bar",
v => v === "foobar"
)
(analogous to if-then-else having multiple else-if sections)
Hm, this is interesting. Although I tend not to add helpers like that if it's just one line more without helper and doesn't needed very often:
const bars = foos.filter(v => v === "bar")
const notBars = foos.filter(v => v !== "bar")
Yet not sure this is what @boneskull wants, because this is exactly the same code as in original comment, and it should work.
Use a false filter after a true one may cause problems, take a look at this:
let doAction;
const playerState = Kefir.stream(e => doAction = e)
.scan((_, act) => `is_${act}`);
const isWalking = playerState.filter(v => v === "is_walk");
const isNotWalking = playerState.filter(v => v !== "is_walk");
isWalking.onValue(() => {
emitter.emit('run');
console.log('player is running');
});
isNotWalking.onValue(() => {
emitter.emit('walk');
console.log('player is walking');
});
You're going to get a maximum call stack error, but it's just a small example that shows these two streams are not updated the same time. One will always update first and cause problems if you subscribe to both of them. My solution is to delay
the second one but the result looks strange and not logical ;)
For more complex predicate you can use:
function complement(pred) { return function(){ return !pred.apply(null, arguments) } }
or inline
Kefir.filter(pred)
Kefir.filter((...args) => !pred(...args))
to avoid code duplication
@pixelpicosean but it's because you actually have infinite loop without any asynchronous calls which will break callstack. But partition method shouldn't be asynchronous, so you'll need delay
anyway
partition seems totally redundant if you use complement
. As far as kefir doesn't implement method sugars which isn't must have. (but maybe I miss something, and there is functional advantage in partition over two filters)
@pixelpicosean Yeah, as @iofjuupasli said you are creating an infinite loop. Here is the logic of your code as it reads to me:
There is an infinite loop by definition, and introducing something like partition
won't help in this case. If you can describe the logic you want (that doesn't include an infinite loop) maybe we find a way to express it in Kefir.
But it seems to me that we might be discussing 3 unrelated topics here :sweat_smile:
@pixelpicosean I'm not understanding your code. Where does emitter
come from?
Yet not sure this is what @boneskull wants, because this is exactly the same code as in original comment, and it should work.
Yes, it works, but it seemed kind of like I shouldn't have to actually write the second lambda.
@rpominov Sorry for bringing another topic, and I just found my problem is a little different from what you are talking about :sweat_smile:
I usually use kefir for game development, which includes tongs of states. The combination of a state
and !state
is very common. I create an example.
ps. FRP is still hard to use for me, but I'm trying to experimenting its the usage in game development which I believe is a uncovered super power for gamedevs. I'd like to hear from you pros :smile:
Yes, it works, but it seemed kind of like I shouldn't have to actually write the second lambda.
I see, you can use something like http://ramdajs.com/0.19.1/docs/#complement then as @iofjuupasli mentioned for removing duplication.
@rpominov To make sure I understand, let me rephrase:
function myFilter(value) {
return value.foo === 'bar';
}
// given "complement" function not()
const notMyFilter = not(myFilter);
stream.filter(myFilter).onValue(value => doSomething(value));
stream.filter(notMyFilter).onValue(value => doSomethingElse(value));
Yes?
@boneskull Yep, seems right.
But yes, then it seems stream.not(otherStream)
would be handy. If the mood hits you to implement such a helper, please consider this one. :smile:
I don't think stream.not(otherStream)
is possible, how do you know for every value from stream
if it was or will be present in otherStream
? We need to look in the future for this.
@pixelpicosean I looked at your example, the problem is that you try to do A filterBy B
where A and B have the same original events source, so it doesn't work well.
There probably no general solutions for this problem I'm afraid, each case needs to be considered separately.
@rpominov I think that makes sense to me.
@pixelpicosean I tried to fix your example http://jsfiddle.net/nd70ebdc/1/ , hopefully I got the intended behavior right :)
@rpominov That looks interesting, but seems not easy to scale. You're right that each case has its own solution. Are there any tricks to implement FSMs, or it is just not necessary?
@pixelpicosean
but seems not easy to scale.
Have to agree with that.
Are there any tricks to implement FSMs
I think it can be done with scan: .scan((state, input) => ...)
Say I have a stream
foos
which usesfilter()
:I want everything in
foos
which is not inbars
(like _.difference()).Naively, you could write:
I thought I might be able to use
diff()
for this, but the documentation makes it sound like it's not applicable.