Skip to content

Instantly share code, notes, and snippets.

@kana-sama
Last active July 24, 2018 16:15
Show Gist options
  • Save kana-sama/29dc32b190c66828e3ebdf323cbfa36d to your computer and use it in GitHub Desktop.
Save kana-sama/29dc32b190c66828e3ebdf323cbfa36d to your computer and use it in GitHub Desktop.
monadic selectors
console.clear();
function compose(...fs) {
return function (...args) {
return fs.reduceRight((args, f) => [f(...args)], args)[0];
};
}
function simpleCheck(a, b) {
return a === b;
}
function simpleCheckArray(a, b) {
if (a.length === 0 && b.length === 0) return true;
if (a.length === 0 || b.length === 0) return false;
const [x, ...xs] = a;
const [y, ...ys] = b;
return simpleCheck(x, y) && simpleCheckArray(xs, ys);
}
function memoize(fn) {
let prevArgs = null;
let prevResult = null;
return function cachedFn(...args) {
if (!prevArgs || !simpleCheckArray(args, prevArgs)) {
prevArgs = args;
prevResult = fn(...args);
}
return prevResult;
};
}
function Do(generatorFunction) {
const generator = generatorFunction();
function next(error, value) {
const res = generator.next(value);
if (res.done) {
return res.value;
} else {
return res.value.chain(value => next(null, value) || res.value.of(value));
}
};
return next();
}
class Selector {
constructor(unwrappedSelector) {
this.unwrappedSelector = memoize(unwrappedSelector);
this.apply = memoize((f, x) => f(x));
}
static of(value) {
return new Selector((state, props) => value);
}
of(value) {
return Selector.of(value);
}
run(state, props) {
return this.unwrappedSelector(state, props);
}
map(fn) {
return new Selector(compose(memoize(fn), this.unwrappedSelector));
}
ap(fn) {
return new Selector((state, props) => {
const x = this.run(state, props);
const f = fn.run(state, props);
return this.apply(f, x);
});
}
join() {
return new Selector((state, props) => {
return this.run(state, props).run(state, props);
});
}
chain(fn) {
return this.map(fn).join();
}
}
const usersEntities = new Selector((state, props) => state.users.entities);
const usersIds = new Selector((state, props) => state.users.ids);
const users_monad = usersEntities.chain(entities => {
return usersIds.chain(ids => {
console.log("recalculate monad");
return Selector.of(ids.map(id => entities[id]));
});
});
const users_applicative = usersEntities.ap(usersIds.map(
ids => entities => {
console.log("recalculate applicative");
return ids.map(id => entities[id]);
}
));
const users_do = Do(function* () {
const ids = yield usersIds;
const entities = yield usersEntities;
console.log("recalculate do");
return Selector.of(ids.map(id => entities[id]));
});
const state = {
users: {
ids: [1, 2, 4],
entities: {
1: { id: 1, name: "kana" },
2: { id: 2, name: "aleph" },
4: { id: 4, name: "andrew" }
}
}
};
const props = {};
console.log("1", users_monad.run(state, props));
console.log("2", users_applicative.run(state, props));
console.log("3", users_do.run(state, props));
console.log(" ");
console.log("4", users_monad.run(state, props));
const newState = { ...state };
// const newState = { users: { ...state.users, ids: [1, 2] } };
console.log("5", users_monad.run(newState, props));
console.log("6", users_monad.run(newState, props));
console.log("7", users_monad.run(state, props));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment