Let's consider the type of gravity1
:
gravity1 :: ([Object], Object) -> SF () (Object)
This is a function that, when provided with a list of Object
and a particular Object
will produce a signal function. This signal function is a so-called generator, meaning that it can be provided with empty input and continually produce a stream of Object
output.
Thus, in essence, gravity1
as two different kinds of inputs:
- It has static input
([Object], Object)
, which it gets once and is forever unchanging, and
- It has streaming input
()
(which is basically equivalent to no streaming input).
With this in mind, it does make sense that, once supplied with its static arguments, gravity1
will produce a constant stream of Object
— after all, it is never receiving updated data about where any Object
s are!
In order to make the output stream dynamically react to changes in the positions of the objects, those positions need to be streaming, not static. In particular, the [Object]
input should be streaming:
gravity1 :: Object -> SF [Object] Object
The other input argument, which specifies the starting position of the Object
we care about, probably doesn't need to be streaming, but it does need to be dealt with carefully (it is only a starting position after all).
But if gravity1
takes the positions of the Object
s as a streaming argument, how will you run it from updateObject
? You will likely need to use some form of delay, such as:
updateObjects :: [Object] -> SF () [Object]
updateObjects objs0 = proc () -> do
rec objs <- iPre objs0 -< objs'
objs' <- parB (fmap gravity1 objs0) -< objs
returnA -< objs'
Incidentally, this strategy of using delay (i.e., the rec
keyword along with iPre
or something similar) is exactly what you'll need to use in gravity1
also to keep track of the current position of the particular object that you're calculating the gravity for.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…