The Santa Claus Problem in Syndicate.js
This commit is contained in:
parent
81ae56d7a8
commit
34723d6f2c
|
@ -0,0 +1,138 @@
|
|||
// bin/syndicatec compiler/demo-santa.js | node
|
||||
//
|
||||
// Santa Claus Problem
|
||||
// https://www.schoolofhaskell.com/school/advanced-haskell/beautiful-concurrency/4-the-santa-claus-problem
|
||||
// https://arxiv.org/pdf/1810.09613.pdf
|
||||
|
||||
var Immutable = require('immutable');
|
||||
var Syndicate = require('./src/main.js');
|
||||
|
||||
assertion type elfProblem(id);
|
||||
assertion type reindeerReturned(id);
|
||||
|
||||
assertion type problemResolved(id);
|
||||
assertion type deliverToys();
|
||||
|
||||
function sleep(milliseconds, continuation) {
|
||||
react {
|
||||
var deadline = +(new Date()) + milliseconds;
|
||||
stop on asserted Syndicate.Timer.timeLaterThan(deadline) {
|
||||
continuation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var elfCount = 0;
|
||||
function elf() {
|
||||
var elfId = "elf" + ++elfCount;
|
||||
spawn* named elfId {
|
||||
function workIndustriously() {
|
||||
console.log(elfId, "is working.");
|
||||
sleep(Math.random() * 1000.0, haveAProblem);
|
||||
}
|
||||
|
||||
function haveAProblem() {
|
||||
console.log(elfId, "has a problem!");
|
||||
react {
|
||||
assert elfProblem(elfId);
|
||||
stop on asserted problemResolved(elfId) {
|
||||
console.log(elfId, "'s problem is resolved.");
|
||||
workIndustriously();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workIndustriously();
|
||||
}
|
||||
}
|
||||
|
||||
var reindeerCount = 0;
|
||||
function reindeer() {
|
||||
var reindeerId = "reindeer" + ++reindeerCount;
|
||||
spawn* named reindeerId {
|
||||
function holiday() {
|
||||
console.log(reindeerId, "is on holiday.");
|
||||
sleep(Math.random() * 9000.0, returnToWork);
|
||||
}
|
||||
|
||||
function returnToWork() {
|
||||
console.log(reindeerId, "has returned from holiday and is ready to deliver toys!");
|
||||
react {
|
||||
assert reindeerReturned(reindeerId);
|
||||
stop on asserted deliverToys() {
|
||||
console.log(reindeerId, "delivers toys with the other reindeer.");
|
||||
react {
|
||||
stop on retracted deliverToys() {
|
||||
console.log(reindeerId, "has been dismissed by Santa.");
|
||||
holiday();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
holiday();
|
||||
}
|
||||
}
|
||||
|
||||
ground dataspace {
|
||||
Syndicate.Timer.spawnTimerDriver();
|
||||
|
||||
var nElves = 20;
|
||||
var elfGroupSize = 3;
|
||||
var nReindeer = 9;
|
||||
|
||||
for (var i = 0; i < nElves; i++) { elf(); }
|
||||
for (var i = 0; i < nReindeer; i++) { reindeer(); }
|
||||
|
||||
spawn* named "Santa" {
|
||||
function waitForWork() {
|
||||
console.log("Santa is waiting for something to do.");
|
||||
react {
|
||||
field this.puzzledElves = Immutable.List();
|
||||
on asserted elfProblem($id) {
|
||||
this.puzzledElves = this.puzzledElves.push(id);
|
||||
}
|
||||
|
||||
field this.readyReindeer = Immutable.List();
|
||||
on asserted reindeerReturned($id) {
|
||||
this.readyReindeer = this.readyReindeer.push(id);
|
||||
}
|
||||
|
||||
stop on (this.puzzledElves.size >= elfGroupSize) {
|
||||
talkToElves(this.puzzledElves.take(elfGroupSize));
|
||||
}
|
||||
stop on (this.readyReindeer.size == nReindeer) {
|
||||
harnessReindeer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function talkToElves(elves) {
|
||||
if (elves.isEmpty()) {
|
||||
waitForWork();
|
||||
} else {
|
||||
var elf = elves.first();
|
||||
console.log("Santa resolves the problem of", elf);
|
||||
react {
|
||||
assert problemResolved(elf);
|
||||
stop on retracted elfProblem(elf) {
|
||||
talkToElves(elves.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function harnessReindeer() {
|
||||
console.log("Santa does the delivery run!");
|
||||
react {
|
||||
assert deliverToys();
|
||||
stop on retracted reindeerReturned(_) {
|
||||
waitForWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waitForWork()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue