134 lines
3.4 KiB
JavaScript
134 lines
3.4 KiB
JavaScript
// 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); }
|
|
stop on (this.puzzledElves.size >= elfGroupSize) {
|
|
talkToElves(this.puzzledElves.take(elfGroupSize));
|
|
}
|
|
|
|
field this.readyReindeer = Immutable.List();
|
|
on asserted reindeerReturned($id) { this.readyReindeer = this.readyReindeer.push(id); }
|
|
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()
|
|
}
|
|
}
|