Coder Social home page Coder Social logo

Comments (7)

webstrand avatar webstrand commented on June 6, 2024

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.

brucou avatar brucou commented on June 6, 2024

@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.

brucou avatar brucou commented on June 6, 2024

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.

adamhaile avatar adamhaile commented on June 6, 2024

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.

brucou avatar brucou commented on June 6, 2024

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.

brucou avatar brucou commented on June 6, 2024

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.

brucou avatar brucou commented on June 6, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.