syndicate-2017/js/compiler/demo-santa.js

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 = 10;
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()
}
}