Some Notes on Signal Usage
-
A
Signalis basically aWidget+looping. SoloopW, which provides stateful looping, is the easiest way to generate individual signals. -
Signals are "continuous", i.e. they always have a current value. So the notion of "merging" signals does not arise except as a zipping operation, where you provide a continuous function which combines individual values from the constituent signals. This "zipping" is possible using monadic bind like so -
do
a <- signal1
b <- signal2
c <- signal3
pure (someFunction a b c)
- If a signal depends on the value of another upstream signal, you can just express that dependency with parameter passing. For example, if
signal2depends on the output fromsignal1, andsignal3depends on the output of bothsignal1andsignal2then -
do
a <- signal1
b <- signal2 a
c <- signal3 a b
pure (someFunction a b c)
- A slight complication occurs when a signal depends on the value of a downstream signal, we need to use the
loopScombinator which "loops" the value of the last signal back up to the top so that the upstream signals can use it. Note that you would need the last signal to carry all the values that are needed by the upstream signals.
Usually you would have some sort of a state that is accessible to all the constituent signals, and loop over that state. In the counter+timer example, the timer and the counter both depended on the current count. So we need to loop the current count over.
- Note that sometimes this changes the final return value of the signal away from what you want. So you may need to
mapthe final composition function on top of the signal value.
To take a pedantic example - if signal1 also depended on the values of signal2 and signal3, we can have signal3 return those values and make them available to signal1 with loopS. Let's assume that the initial values for signal2 is initialB and for signal3 is initialC.
loopS {b:initialB, c:initialC} \{b, c} -> do
a <- signal1 b c
b' <- signal2 a
c' <- signal3 a b'
pure {b:b', c:c'}
But now the final value of the signal is Tuple b c. So we need to fix that. We need to add the value of signal1 to the output since that's needed in the final output, and then map over with someFunction -
s = g <$> innerSignal
where
g {a,b,c} = someFunction a b c
innerSignal = loopS {a:initialA, b:initialB, c:initialC} \{b, c} -> do
a' <- signal1 b c
b' <- signal2 a'
c' <- signal3 a' b'
pure {a:a', b:b', c:c'}
Not pretty, but usually you won't have such complicated state and dependencies.