Skip to content

Instantly share code, notes, and snippets.

@HerringtonDarkholme
Created August 19, 2015 17:23
Show Gist options
  • Save HerringtonDarkholme/b1c52b2a899de0043b4f to your computer and use it in GitHub Desktop.
Save HerringtonDarkholme/b1c52b2a899de0043b4f to your computer and use it in GitHub Desktop.
/// <reference path='./es6-collections.d.ts' />
declare var require: any
require('es6-collections')
class Caller<T> {
private callers: T[] = []
constructor(init?: T) {
if (init !== undefined) this.callers.push(init)
}
withValue(t: T): Function {
if (this.callers.indexOf(t) >= 0) throw new Error('cyclic!')
return (fn: Function) => {
this.callers.push(t)
let ret = fn()
console.log(fn.toString())
this.callers.pop()
return ret
}
}
get value() {
return this.callers[this.callers.length-1]
}
}
class Signal<T> {
private value: T
protected expr: () => T
private observees: Array<Signal<{}>> = []
private observers: Set<Signal<{}>> = new Set<any>()
constructor(expr: () => T) {
this.expr = expr
this.computeValue()
}
computeValue(): void {
for (let sig of this.observees) {
sig.observers.delete(this)
}
this.observees = []
let newValue = caller.withValue(this)(this.expr)
if (this.value !== newValue) {
this.value = newValue
var obs = this.observers
this.observers = new Set<any>()
obs.forEach((o) => o.computeValue())
}
}
update(t: () => T) {
this.expr = t
this.computeValue()
}
apply() {
let callSig = caller.value
this.detectCyclicRecursive(callSig)
this.observers.add(callSig)
callSig.observees.push(this)
return this.value
}
detectCyclicRecursive(callSig: Signal<{}>) {
if (callSig.observers.has(this)) {
throw new Error('cyclic signal definition')
}
callSig.observers.forEach(call => this.detectCyclicRecursive(call))
}
}
class Var<T> extends Signal<T> {
}
class NoSignal extends Signal<{}> {
constructor() {super(() => void 0)}
computeValue() {}
}
var caller = new Caller<Signal<any>>(new NoSignal)
var a = new Signal(() => void 0)
var b = new Signal(() => void 0)
var c = new Signal(() => void 0)
a.update(() => {b.apply();return Math.random()})
b.update(() => {c.apply(); return Math.random()})
c.update(() => {return a.apply() +Math.random()})
console.log(c.apply())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment