Skip to content

Instantly share code, notes, and snippets.

@mattpodwysocki
Last active December 27, 2015 10:39
Show Gist options
  • Save mattpodwysocki/7312324 to your computer and use it in GitHub Desktop.
Save mattpodwysocki/7312324 to your computer and use it in GitHub Desktop.
Observable.scan
Rx.Observable.prototype.scan = function (/* [seed], accumulator */) {
var hasSeed = false, seed, accumulator, source = this;
if (arguments.length === 2) {
hasSeed = true;
seed = arguments[0];
accumulator = arguments[1];
} else {
accumulator = arguments[0];
}
return Rx.Observable.createWithDisposable(function (observer) {
var hasAccumulation, accumulation, hasValue;
return source.subscribe (
function (x) {
try {
if (!hasValue) {
hasValue = true;
}
if (hasAccumulation) {
accumulation = accumulator(accumulation, x);
} else {
accumulation = hasSeed ? accumulator(seed, x) : x;
hasAccumulation = true;
}
} catch (e) {
observer.onError(e);
return;
}
observer.onNext(accumulation);
},
observer.onError.bind(observer),
function () {
if (!hasValue && hasSeed) {
observer.onNext(seed);
}
observer.onCompleted();
}
);
});
};
function add(x, y) { return x + y; }
function createObserver(num) {
return Rx.Observer.create(
function (x) {
console.log('next ' + num + ':' + x);
},
function (e) {
console.log(e.message);
},
function () {
console.log('completed ' + num);
}
);
}
// Usage
var obs1 = Rx.Observable.empty().scan(add);
var obs2 = Rx.Observable.empty().scan(0, add);
var obs3 = Rx.Observable.range(1, 3).scan(add);
var obs4 = Rx.Observable.range(1, 3).scan(0, add);
obs1.subscribe(createObserver(1));
// => completed 1
obs2.subscribe(createObserver(2));
// => next 2:0
// => completed 2
obs3.subscribe(createObserver(3));
// => next 3:1
// => next 3:3
// => next 3:6
// => completed 3
obs4.subscribe(createObserver(4));
// => next 4:1
// => next 4:3
// => next 4:6
// => completed 4
@cwharris
Copy link

cwharris commented Nov 5, 2013

The following expected result would break compatibility with the .NET implementation.

// => next 2:0

Is that intentional?

See here: https://gist.github.com/cwharris/7321527

@mattpodwysocki
Copy link
Author

This is to conform to Haskell:

scanl (+) 0 [] == [0]

scanl1 (+) [] == []

Or even F#:

Seq.empty<int> |> Seq.scan (+) 0
// => [0]

@cwharris
Copy link

cwharris commented Nov 5, 2013

Interesting. And actually, this makes more sense. If there is a seed, the seed is presumably the identity of the function under its parameter types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment