Skip to content

Instantly share code, notes, and snippets.

@joneshf
Last active August 29, 2015 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joneshf/06589f99ad05cb159da0 to your computer and use it in GitHub Desktop.
Save joneshf/06589f99ad05cb159da0 to your computer and use it in GitHub Desktop.
var R = require('ramda');
var Type = require('union-type-js');
// We need a base set of states: {`Q0`, `Q1`, `Q2`}.
var State = Type({Q0: [], Q1: [], Q2: []});
// We need an input alphabet: {`A`, `B`}.
var Sigma = Type({A: [], B: []});
// We need a transition function
// that takes a state and an element of the alphabet, and gives a new state.
var delta = R.curry(function(state, sigma) {
return State.case({
Q0: R.always(Sigma.case({
A: R.always(State.Q1()),
B: R.always(State.Q0())
}, sigma)),
Q1: R.always(Sigma.case({
A: R.always(State.Q2()),
B: R.always(State.Q1())
}, sigma)),
Q2: R.always(Sigma.case({
A: R.always(State.Q0()),
B: R.always(State.Q2())
}, sigma)),
}, state);
});
// We need a function that takes a state,
// and gives an element in the output alphabet.
// The output alphabet is: {`In state Q0`, `In state Q1`, `In state Q2`}.
var output = State.case({
Q0: R.always("In state Q0"),
Q1: R.always("In state Q1"),
Q2: R.always("In state Q2")
});
// Now we create a `Moore` machine.
// Moore : s -> (s -> sigma -> s) -> (s -> lambda) -> Moore sigma lambda
function Moore(s0, delta, out) {
this.state = s0;
this.delta = delta;
this.out = out;
}
// map : Moore sigma lambda => (lambda -> nu) -> Moore sigma nu
Moore.prototype.map = function(f) {
return new Moore(this.state, this.delta, R.pipe(this.out, f));
};
// promap : Moore sigma lambda => (tau -> sigma) -> (lambda -> nu) -> Moore tau nu
Moore.prototype.promap = R.curry(function(f, g) {
var delta = this.delta;
var epsilon = R.curry(function(state, sigma) {
return delta(state, f(sigma));
});
return new Moore(this.state, epsilon, R.pipe(this.out, g));
});
// lmap : Moore sigma lambda => (tau -> sigma) -> Moore tau lambda
Moore.prototype.lmap = function(f) {
return this.promap(f, R.identity);
};
// step : Moore sigma lambda => sigma -> Moore sigma lambda
Moore.prototype.step = function(sigma) {
return new Moore(this.delta(this.state, sigma), this.delta, this.out);
};
// output : Moore sigma lambda => lambda
Moore.prototype.output = function() {
return this.out(this.state);
};
var moore = new Moore(State.Q0(), delta, output);
console.log(moore.output()); //=> In state Q0
var moore2 = moore.step(Sigma.B());
console.log(moore2.output()); //=> In state Q0
var moore3 = moore2.step(Sigma.A());
console.log(moore3.output()); //=> In state Q1
var moore4 = moore2.map(R.toUpper).step(Sigma.A());
console.log(moore4.output()); //=> IN STATE Q1
var Sigma2 = Type({C: [], D: []});
// This will break because `moore` only knows about `Sigma`
// moore.step(Sigma2.C());
// But if we provide some way to go from a `Sigma2` to a `Sigma`,
// we're all good!
// This maps `C -> B` and `D -> A`.
var convert = Sigma2.case({
C: R.always(Sigma.B()),
D: R.always(Sigma.A())
});
var moore5 = moore3.lmap(convert).step(Sigma2.D());
console.log(moore5.output()); //=> In state Q2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment