Comments (7)
If I understand correctly, then scan
would be simply:
var stream = S.data(0);
var scanned = S((acc) => stream() + acc, 0);
S(() => console.log(scanned()));
stream(1);
stream(3);
stream(5);
//0
//1
//4
//9
from s.
@webstrand mmm. That does seem like so, I'll see how it works in my use case. Don't see how that escaped me, it is pretty simple indeed. Actually I may not even need scan
anymore,,, The totality of the variables depend on a single signal. Thanks!
from s.
Alright, after fighting a few hours with this, the conclusion is that it is pretty unnatural (not to say impossible) to refer to the previous values of signals with the current API (keep running in circular dependency warning). So a scan
may be the best way to go forward. But then if all variables are put in one giant scan
there is no longer any point in using S.js... My idea was to write synchronous equations with it, like in dataflow languages.
To summarize the problem:
- I want Yn = f(Yn-1, Xn-1), Xn = f(Xn-1)
- S( val => ..., seed) only allows Sn = f(Sn-1)
If somebody is interested in investigating, the (not working) S code is here. The working Rxjs code is here. If no answer in a few days, I will close this.
from s.
Lucid Synchrone is definitely an influence on S :).
S doesn't have a global ability like Lucid Synchrone's pre
keyword because S is a library, not a compiler. That means S doesn't know ahead of time which values need to have their previous values retained. So it would have to store all previous values, even though very few will actually be read. That would be a global cost and an avenue for memory leaks.
So instead, you have to tell S which signals you want to keep the previous value for. There are a few ways to write that function -- I see one in your code but yeah, it's not the one you want, because it depends on the current value, which for your purposes creates a cycle.
You may have better luck with a definition like this:
const prev = (s, init) => {
const _prev = S.data(init);
S(() => _prev(s()));
return _prev;
}
That uses a data signal to store the value of the signal from the previous tick without creating a dependency in consumers on the current value as well.
All that said, I generally find games and other "forward integration"-style programs much easier to write based on a "current, next" pattern rather than a "previous, current" one. In effect, that means putting game state into data signals instead of computations. Computations become the "rules" that update the data signals representing game state. But that does mean that the new state doesn't become current until the tick after the event advancing the game occurs, so it breaks synchrony.
from s.
Thanks @adamhaile. That seems to make sense. I still have to make an intuition of this S syntax. I can see why prev is updated when s is, but not why it is deferred in time. In the beginning it is obvious, prev
is init
. the confusion comes after. I will try though.
I agree about the current, next
approach working better. In fact, revising my pseudo-code vs. Rxjs implementation, I am realizing that most of the equations on the right side involves previous values of streams... But then, how would you write a next
operator? Is that even possible?
Putting game state in data signals as you suggest should work too. I wanted somehow to derive everything from the user click on the chess board, as user clicks work as a clock signal that drives all the computations. That looks like a more declaratve approach. The esterel dataflow language has a more imperative approach where you listen on signals and emit values in signals manually. That seems similar to what you are suggesting here?
Anyways, I'll try again today. Hopefully I meet success and I can report it here.
from s.
Thanks all of you for your support. I made some progress, but now I have a stubborn runaway clock error (see updated codesandbox), and I am giving up here. Spent too much time already. It may very well be possible to do what I want with S.js (for instance as @adamhaile suggested putting game state in data signals) but the bottomline is that if I have to spend this amount of time and still fail, it is not the good tool for me. What I would suggest for future beginners:
- add examples in the docs that go beyond the simple use cases
- develop some more the trouble shooting section from the notes on runaway mutation
- not sure if it is possible, but tracing the computation or logging the dependency tree would be helpful for debugging
Thanks again
from s.
Coming back to this and adding this jsfiddle:
https://jsfiddle.net/7w1bcg69/4/
var prev = (s, init) => {
const _prev = S.data(init);
S(() => _prev(s()));
return _prev;
}
var counter = S.data(0);
var prevCounter = prev(counter, -8);
S.effect(() => console.log(`counter`, counter()))
S.effect(() => console.log(`prev counter`, prevCounter()))
var dep = S(() => counter() + prevCounter());
S.effect(() => console.log(`dep`, dep()))
document.getElementById("btn").addEventListener("click", ev => counter(counter()+1))
Console (init and then one button click):
JSFiddle Console (beta). Turn on/off in Editor settings.
☁️ "Running fiddle"
"computations created without a root or parent will never be disposed"
"counter", 0
"prev counter", 0
"computations created without a root or parent will never be disposed"
"dep", 0
"counter", 1
"dep", 1
"prev counter", 1
"dep", 2
Expected behavior:
dep
should update only once. prev counter
should start with its configured initial value (-8). And then prevCounter should equal the previous value of the counter.
from s.
Related Issues (20)
- Karma / Jest testing HOT 9
- Just took it for a first drive....
- Push to array data signal HOT 1
- Creating computations when resolving Promises HOT 2
- Maps HOT 12
- Are subclocks generally available? HOT 4
- Computations creating signals HOT 10
- Make methods treeshake-able HOT 3
- Root + Async = Headaches HOT 5
- Cleanup single computation HOT 1
- S.value multiple updates with no listeners fail HOT 1
- Conditionally triggering downstream computations HOT 3
- Can this nested computation behavior be explained? HOT 2
- Recommended way to deal with "Runaway clock detected"? HOT 1
- Handling Nested Computations under Branching Logic HOT 13
- Why prevent signals from setting different pending values in a single clock tick? HOT 1
- Local state inside effect / hooks HOT 2
- Compute value with prev != next check
- cleanup and update phases are intermingled HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from s.