turion / rhine

Haskell Functional Reactive Programming framework with type-level clocks
http://hackage.haskell.org/package/rhine
118 stars 21 forks source link

Article Example Application Behaves Erratically #214

Closed Cajunvoodoo closed 1 year ago

Cajunvoodoo commented 1 year ago

I was working through the article linked in the readme and reimplemented the extended example. It involves a physics simulation of a ball falling. When stdin is triggered, "Catch!" is supposed to appear, followed by intermittent (500ms) reports of the ball position. The output of my reimplementation did not behave as expected.

Expected:

0.00 0.00 0.00
0.00 0.00 0.00
Catch!
1.09 1.51 3.08
2.39 3.31 4.49
3.68 5.11 3.44
Caught!
0.00 0.00 0.00
...

Actual:

0.00 0.00 0.00
0.00 0.00 0.00
0.00 0.00 0.00
0.00 0.00 0.00
0.00 0.00 0.00

Catch!
Caught!
Catch!
Caught!
Catch!
Caught!
Catch!
Caught!
...

Note the repeated Catch and Caughts are from a single input of the enter key.

My reimplementation (paste.debian.net)

turion commented 1 year ago

Thanks, I can reproduce this. Investigating.

turion commented 1 year ago

I can actually not exactly reproduce it. What I can reproduce: When I do a single enter key input, it works as advertised. When I do several key presses in quick succession, I get the issue you show.

turion commented 1 year ago

Apologies, sometimes I can reproduce the problem with a single key stroke.

turion commented 1 year ago

There is an important difference between the article version and your version:

Article:

velZ <- randomRIO ( 3, 10)

Your version:

velZ <- randomRIO (-10, 10)

In your version, the ball can launch with negative velocity into the ground. Then of course it must be immediately caught. The trouble now is that in this case, falling doesn't output any values (because it immediately catches), so it doesn't even consume the event. So we're caught in an endless loop where the event is never consumed, and only side effects are produced.

If you want to keep the negative vertical velocity, you can work around this by delaying the "Caught" event:

--   throwMaybe -< guard $ height < 0 -- article/your version
  throwMaybe <<< iPre Nothing -< guard $ height < 0

So in summary, it seems like there is no problem with the article or the library. It's unfortunate that even with rhine, one can still write programs that get caught in infinite loops, but that's always the case when one has recursion without coinductive types. So I'll close for now, but feel free to reopen if this doesn't solve the problem for you.