Skip to content

Commit

Permalink
Add a basic State monad
Browse files Browse the repository at this point in the history
  • Loading branch information
earldouglas committed Oct 7, 2015
1 parent 7c41a5e commit 34b8a27
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 9 deletions.
35 changes: 35 additions & 0 deletions src/teep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,40 @@ module edc {

var readerT = <A,B>(f: (A) => Monad<B>) => { return new ReaderT(f); }

class StateTuple<S,A> {
state: S;
value: A;
constructor(s: S, a: A) {
this.state = s;
this.value = a;
}
}

var state = <S,A>(f: (S) => StateTuple<S,A>) => { return new State(f); }

class State<S,A> {
f: (S) => StateTuple<S,A>;
constructor(f: (S) => StateTuple<S,A>) {
this.f = f;
}
apply(s: S): StateTuple<S,A> {
return this.f(s);
};
map<B>(g: (A) => B): State<S,B> {
return state((s: S) => {
var sa: StateTuple<S,A> = this.f(s);
return new StateTuple(sa.state, g(sa.value));
});
};
flatMap<B>(g: (A) => State<S,B>): State<S,B> {
return state((s: S) => {
var sa: StateTuple<S,A> = this.f(s);
var sb: State<S,B> = g(sa.value);
return sb.apply(sa.state);
});
};
}

export var teep = {
array: array,
fn: fn,
Expand All @@ -399,6 +433,7 @@ module edc {
read: read,
future: future,
readerT: readerT,
state: state,
};

var setExports = function () {
Expand Down
38 changes: 37 additions & 1 deletion teep.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,41 @@ var edc;
return ReaderT;
})();
var readerT = function (f) { return new ReaderT(f); };
var StateTuple = (function () {
function StateTuple(s, a) {
this.state = s;
this.value = a;
}
return StateTuple;
})();
var state = function (f) { return new State(f); };
var State = (function () {
function State(f) {
this.f = f;
}
State.prototype.apply = function (s) {
return this.f(s);
};
;
State.prototype.map = function (g) {
var _this = this;
return state(function (s) {
var sa = _this.f(s);
return new StateTuple(sa.state, g(sa.value));
});
};
;
State.prototype.flatMap = function (g) {
var _this = this;
return state(function (s) {
var sa = _this.f(s);
var sb = g(sa.value);
return sb.apply(sa.state);
});
};
;
return State;
})();
edc.teep = {
array: array,
fn: fn,
Expand All @@ -367,7 +402,8 @@ var edc;
reader: reader,
read: read,
future: future,
readerT: readerT
readerT: readerT,
state: state
};
var setExports = function () {
array.map(object.keys(edc.teep), function (k) {
Expand Down
58 changes: 50 additions & 8 deletions test/examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,22 @@ describe('examples', function () {
}
return n;
}

var t1 = Date.now();
var lazyVal = teep.fn.lazy(expensiveFn)(42); // lazily apply 42 -- no computation yet
var t2 = Date.now();

var t3 = Date.now();
var slowResult = lazyVal.get(); // expensive computation the first time
var t4 = Date.now();
var fastResult = lazyVal.get(); // cheap cache lookup the second time
var t5 = Date.now();

assert.equal(slowResult, 42);
assert.equal(fastResult, 42);

assert.ok(t2 - t1 < 10); // roughly immediate

var slow = t4 - t3;
var fast = t5 - t4;
assert.ok(slow > 10 * fast); // over 10x faster
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('examples', function () {
], function (x, y, z) {
return x * (y + z);
});

p.then(function (x) {
assert.equal(x, 42);
done();
Expand Down Expand Up @@ -407,15 +407,15 @@ describe('examples', function () {
return k(x);
};
};

var asyncF = function (f) {
return function (x) {
return teep.future(function (k) {
return k(f(x));
});
};
};

var verify = function (done) {
return function (y) {
if (42 === y) {
Expand Down Expand Up @@ -495,4 +495,46 @@ describe('examples', function () {

});

describe('state', function () {

var db = {
answer: 42,
};

var getAnswer = teep.state(function (db) {
return { state: db, value: db.answer };
});

var addToAnswer = function(x) {
return teep.state(function (db) {
db.answer = db.answer + x;
return { state: db, value: null };
});
}

it('apply', function () {
var result = getAnswer.apply(db);
assert.deepEqual(42, result.value);
});

it('map', function () {
var result =
getAnswer.map(function (x) {
return x + 1;
}).apply(db);
assert.deepEqual(43, result.value);
});

it('flatMap', function () {
var result =
getAnswer.flatMap(function (x) {
return addToAnswer(x / 2);
}).flatMap(function (x) {
return getAnswer;
}).apply(db);
assert.deepEqual((42 / 2) + 42, result.value);
});

});

});

0 comments on commit 34b8a27

Please sign in to comment.