Comments (4)
The only one of these that we can generate code for right now is delay
, the rest are not possible since we can not generate code for polymorphic functions (yet).
from scoria.
This is a really simple combinator, but it would be nice to have an infinite loop combinator
loop :: SSM () -> SSM ()
loop = while' true'
would also be great to have a do-while loop kind of construct:
doWhile :: Exp Bool -> SSM () -> SSM ()
doWhile c b = b >> while' c b
note that doWhile c b
isn't very structurally evocative, unlike C's do { b } while (c)
, so we might want to rename that.
until
is another good one to have:
until :: Exp Bool -> SSM () -> SSM ()
until c = while $ not c
All basic sugar, but nice to have when writing programs.
from scoria.
One-shot and its variations:
Basic one-shot:
oneShot :: SSMTime -> Bool -> Ref () -> Ref Bool -> SSM ()
oneShot delay low i o = while True $ do
wait [i]
o <~ not low
after delay, o <~ low
A more type-generic version that acts more like a functor, mapping over values of the input reference:
oneShotMap :: SSMTime -> Exp b -> (Exp a -> Exp b) -> Ref a -> Ref b -> SSM ()
oneShotMap delay low f i o = while True $ do
wait [i]
o <~ f (deref i)
after delay, o <~ low
We can redefine oneShot
using oneShotMap
:
oneShot delay low = oneShotMap delay low (const $ not low)
For the following variations, I'll use the type-specific version for brevity.
The above implementation will issue an additional instantaneous assignment if it receives two consecutive input signals before it is able to reset the output signal. While the additional assignment may seem redundant, it has the effect of waking up waiting processes (though with no change in value). That may or may not be desirable. This implementation ensures that only alternating assignments are made:
oneShot' :: SSMTime -> Exp Bool -> Ref () -> Ref Bool -> SSM ()
oneShot' delay low i o = while True $ do
wait [i]
when (deref o != low) $ o <~ not low
after delay, o <~ low -- extends scheduled shut-off time
Note that if the scheduled o <~ low
update takes place at the exact same time that input is received on i
, o
will be assigned to twice in the same instant, with different values.
Meahwhile, if we wanted to imitate the behavior of the one-shot circuit shown here, we need to make a few changes. First, the input needs to be a Ref Bool
as well, to remain faithful to the circuit analogy. We only respond to rising edges. We also need to ignore repeated assignments of the same value. Secondly, we need to make sure that once we've received a rising edge input, we ignore subsequent input until we've written low
value.
oneShotW :: SSMTime -> Exp Bool -> Ref Bool -> Ref Bool -> SSM ()
oneShotW delay low i o = while True $ do
-- wait until i <~ true
while True $ do
wait [i]
when (deref i) $ break
-- raise o
o <~ not low
-- set alarm
wake <- var ()
after delay, wake <~ ()
wait [wake]
-- reset o
o <~ low
Note that here we use an internal alarm rather than waiting on o
, because we can't assume we are the only process writing to o
. This inadvertently solves another issue: in the previous examples, we mixed instananeous assignments with delayed assignments to o
, such that all processes would see the delayed o <~ low
assignment, but only processes of lower priority would see the instananeous o <~ not low
assignment, creating an odd asymmetry that leads to unexpected behavior. For instance, if o
is an output LED with a higher priorirty output handler, the output handler would never turn on the LED, but will receive low
signals to o
that could clobber other concurrent signals.
The implementation of oneShotW
is such that we only ever use instanenous assignment on o
, so that only lower priority processes will be able to see writes by oneShotW
to o
. A high priority output handler still wouldn't be able to receive output to the LED, but at least the output handler is uniformly deaf to both o <~ not low
and o <~ low
.
The fact that oneShotW
uses instantaneous assignment precludes the use of high priority output handlers for o
that can only evaluate delayed updates. We can adjust the implementations of oneShotW
and oneShot'
to only use delayed assignment, parametrized by some small latency that is used in place of the instananeous assignment:
oneShotW_ :: SSMTime -> SSMTime -> Exp Bool -> Ref Bool -> Ref Bool -> SSM ()
oneShotW_ latency delay low i o = while True $ do
-- wait until i <~ true
while True $ do
wait [i]
when (deref i) $ break
-- raise o
after latency, o <~ not low
-- set alarm
wake <- var ()
after delay, wake <~ ()
wait [wake]
-- reset o
after latency, o <~ low
oneShot'_ :: SSMTime -> SSMTime -> Exp Bool -> Ref () -> Ref Bool -> SSM ()
oneShot'_ latency delay low i o = while True $ do
wait [i]
when (deref o != low) $ after latency, o <~ not low
after (latency + delay), o <~ low
We have a number of interesting combinators that we can extract from this example.
This one translates instantaneous assignments to one variable to delayed assignments on another. When scheduled as a low priority process, this can be used to forward instananeous assignments to high priority output handlers:
latency :: SSMTime -> Ref a -> Ref a -> SSM ()
latency d i o = while True $ do
wait [i]
after d, o <~ deref i
The idea is that latency
introduces a short but necessarily and predictable amount of latency to enable high priority output handlers.
This implementation assumes that i != o
. If the are the same, this implementation will misbehave terribly, spamming the system with writes due to a feedback loop.
With the current runtime system, there isn't a way to distinguish between an instantaneous and delayed assignment. Having such a feature may be useful for writing low-priority processes that convert only instantaneous assignments into delayed assignments, i.e., mimicking a default delay.
From oneShotW
, we can extract a waitUntil
combinator:
waitUntil :: [Ref a] -> SSMExp Bool -> SSM ()
waitUntil refs cond = while True $ wait refs >> when cond break
from scoria.
"The fact that oneShotW uses instantaneous assignment precludes the use of high priority output handlers for o that can only evaluate delayed updates. We can adjust the implementations of oneShotW and oneShot' to only use delayed assignment, parametrized by some small latency that is used in place of the instananeous assignment"
This sounds like a really good place for adding perhaps a new primitive RTS function. Immediate assignment which wakes up everyone. This primitive would be available only to us as compiler developers, and not exposed to programmers. Or perhaps it could be, but very well documented and with a name like pleaseDoNotUseImmediateAssignment
, similar to stuff like unutterablyUnsafePerformIO
and so on.
Things like the latency
operator, if you call it just like that, it's going to make your program halt there forever, right? It sounds like a good combinator but we need to think of a nice way of using it.
from scoria.
Related Issues (20)
- Implement unit type as SSMType HOT 4
- Even better shrinker! HOT 2
- Can't use references in operators HOT 6
- SSM time types for frontend HOT 9
- Lower deref from statement level to expression level HOT 1
- Profile interpreter to see if it's the culprit that makes the tests take longer than previously HOT 3
- Transpilation bug - names are duplicated HOT 4
- Ask Zephyr people about 64bit timers
- Refactor interpreter
- Connect standard streams to global references HOT 1
- Make expressions compile to ordinary types in C, not scheduled variables HOT 1
- Remove arguments to the entry point HOT 1
- Inefficient distribution of priorities HOT 1
- Propagate parse errors from trace parsers to testing framework
- Make core syntax more fine grained
- Examples wishlist HOT 2
- Don't assume long == 64-bit
- Add "escape hatch" in EDSL HOT 2
- Integer overflow in interpreter might be UB HOT 1
- [RFC] Output handlers HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from scoria.