loop : a -> { send : Signal a -> Signal a,
recv : Signal a }
First look at the record returned.
- `send` takes in a signal and returns the same signal. The trick is that it also pipes the values through to `recv`.
- `recv` is the "looped signal". The "looped signal" are the values that have been sent with the `send` function.
The argument to `loop` is the base case for the "looped signal". An example usage would be:
playing = loop True
game = foldp step startState (30 `fpsWhen` playing.recv)
programSaysPlay = playing.send (dropRepeats (.play <~ game))
main = display <~ game
In this example, game is the thing we'd like to show on screen. It has a field game.play which indicates whether the it should keep updating. We want to only give FPS when game.play is true. So we send game.play through our loop and give it to fpsWhen. This example is weird in that there is no way to unpause, but I wanted to keep it simple.
This is unsafe so you must personally add some kind of filter. I chose to use dropRepeats, but any other filter would work.
Jeff's Loop without special syntax (Safe Loop):
I think there is a way to allow safe loops without special syntax. As I understand, the key features are: allow arbitrary loops, block infinite loops by tying updates to another signal.
loop : a -> { send : Signal a -> Signal a,
sampleOn : Signal b -> Signal a }
First look at the record returned.
- `send` takes in a signal and returns the same signal. The trick is that it also pipes the values through to the `sampleOn` function.
- `sampleOn` takes an arbitrary signal (as a trigger) and returns the "looped signal" which only updates when the trigger is updated. The "looped signal" are the values that have been sent with the `send` function.
The argument to `loop` is the base case for the "looped signal". An example usage would be:
myLoop = loop True
playing = myLoop.sampleOn Mouse.clicks
game = foldp step startState (30 `fpsWhen` playing)
programSaysPlay = myLoop.send (.play <~ game)
main = display <~ game
This demonstrates the issue that events only come through if the user clicks the mouse, but I think it illustrates the idea. Does this miss any key aspect of Jeff's proposal? If so, I probably have misunderstood something, so sorry in advance.
Other thoughts:
It seems like there may be many filtering techniques that could be useful for loops. One idea is to only provide safe loops, as in Jeff's proposal. I like this, but I also think there would need to be a family of looping constructs to permit all of the kinds of safe loops you'd want. (loop + dropRepeats, loop + sampleOn, loop + ?)
It also seems like there may be some restrictions we can impose on the Unsafe Loop. Something like: no loop update can trigger another loop update (e.g. loops only go around once). I think there are problems with that particular restriction, but this general idea may be have nice results.