* Currently all Inputs run each time through the loop, which could be a
problem when an input is slow. It would be good if the @: operator could
also rate limit when Inputs occur.
Copilot does not let `extern` be limited, but the actual input operation
is done by ardino-copilot's readInput, and extern then just uses the
value it sets. So, make each Input add a trigger, that sets a flag
variable, and in readInput just check if the flag is set.
It should be possible to implement this w/o adding overhead when @: is
not used on an Input. Either, avoid checking the flag in this case,
or check that the C compiler can optimise away a check of a flag that
always succeeds.
(Note that, if @: makes the first read be skipped, or all of them,
there would need to be a default value produced. Or, to avoid default
values, it could force the first read to always occur.)
An Input returns a Behavior; with @: it should really return an Event.
But, that would need boilerplate to get the Stream out to use.
- foo <- input pin4
+ Event foo _ <- input pin4 @: longer_and_longer
pin5 =: streamfunc foo
Seems not worth the distinction of Behavior vs Event here.
* If @: could somehow be applied to a whole Sketch () action, it would be
possible to write some interesting combinators based on it, eg:
ifM :: Stream Bool -> Sketch a -> Sketch a -> Sketch a
schedule :: Stream Int -> [(Int, Sketch a] -> Sketch a
Although, it may be that these would cause some explosion of the binary
size, since each trigger in a Sketch's guard would, presumably, turn
into a C function that duplicates the same code. Perhaps the C compiler
could notice the common expressions and optimise them?
Anyway, this would need the Sketch () to contain not a Spec, which I
think is too opaque, but a data structure that allows adjusting the
guards of `trigger` and an equivilant guard be added for `extern`.
(See also, previous item.) And, it pushes things in the direction of
needing to support multiple calls to Serial.display and wait with
different parameters, and generally never hardcode the name of the C
function called by a trigger.
Now, I like the way that @: currently turns a behavior into an event, in
FRP style. If @: is applied to a whole Sketch, it would stop doing that.
That feels like a loss. So, perhaps @: stays as-is, and there's a new
combinator to do the same thing to a Sketch. Internally, they would both
adjust the guards of triggers. A bit redundant, but seems worth it to
keep @: FRP style. (Making @: more polymorphic is also a possibility.)
Another combinator, that I considered but rejected is:
(|:) :: Sketch a -> Sketch a -> Sketch a
The problem with this is that in foo |: bar |: baz, one of the
three never runs, because both combinators must branch on the same
Stream Bool.
* analogReference()
Takes one of a set of defines, which vary depending on board,
so how to pass that through Copilot? Could write a C
switch statement, on an int, and have the boade modules define
effectively enums.
* Voltage is a raw ADC value; add a stream function to convert that
to a floating point actual voltage, given also a stream that contains
the reference voltage.
* pulses
* random numbers
* Wire library
* test.hs is not wired into the cabal file because it depends on runghc
having the library available