Open getify opened 2 years ago
OK, so at @DrBoolean's sage observation, this can be generalized to support any monoid (not just strings) without too much complexity:
var id = IO.of(42);
doBuilder(whatever,v => (typeof v == "string"),[ id ])
.map(v => console.log("html",v))
.run({});
function *whatever(context,id) {
yield `<div id="${id}">`;
for (let i = 0; i < 3; i++) {
yield `<span>${i}</span>`;
}
yield `</div>`;
}
And the implementation of doBuilder(..)
:
function doBuilder(
doRoutine,
isMonoid = v => (v && typeof v.concat == "function"),
deps = [],
...args
) {
return IOx.do(runner,deps);
// ************************************
async function *runner(context,...depsVals) {
var concatIO = IO.of("");
var it = doRoutine(context,...depsVals,...args);
var res;
while (true) {
res = it.next(res);
if (isPromise(res)) {
res = await res;
}
else {
let done = res.done;
if (isMonad(res.value)) {
if (IO.is(res.value)) {
res = res.value.chain(concatIfMonoid);
}
else if (Nothing.is(res.value)) {
return IO.of("");
}
else if (Either.is(res.value) || Maybe.is(res.value)) {
res = res.value.fold(IO.of,concatIfMonoid);
}
else {
res = res.value.fold(concatIfMonoid);
}
}
else {
res = concatIfMonoid(res.value);
}
res = yield res;
if (done) {
return concatIO.run(context);
}
}
}
// ************************************
function concatIfMonoid(v) {
if (isMonoid(v)) {
concatIO = concatIO.concat(IO.of(v));
return IO.of();
}
else {
return IO.of(v);
}
}
}
}
Next revision/abstraction:
var id = IO.of(42);
strBuilderX(whatever,[ id ])
.map(v => console.log("html",v))
.run({});
function *whatever(context,id) {
yield `<div id="${id}">`;
for (let i = 0; i < 3; i++) {
yield `<span>${i}</span>`;
}
yield `</div>`;
}
And the updated implementation:
function strBuilder(doRoutine,...args) {
var runner = buildRunner(doRoutine,v => (v && typeof v == "string"),...args);
return IO.do(runner);
}
function strBuilderX(doRoutine,deps = [],...args) {
var runner = buildRunner(doRoutine,v => (v && typeof v == "string"),...args);
return IOx.do(runner,deps);
}
function buildRunner(doRoutine,isMonoid = v => (v && typeof v.concat == "function"),...args) {
return async function *runner(context,...depsVals){
var concatIO = IO.of("");
var it = doRoutine(context,...depsVals,...args);
var res;
while (true) {
res = it.next(res);
if (isPromise(res)) {
res = await res;
}
else {
let done = res.done;
if (isMonad(res.value)) {
if (IO.is(res.value)) {
res = res.value.chain(concatIfMonoid);
}
else if (Nothing.is(res.value)) {
return IO.of("");
}
else if (Either.is(res.value) || Maybe.is(res.value)) {
res = res.value.fold(IO.of,concatIfMonoid);
}
else {
res = res.value.fold(concatIfMonoid);
}
}
else {
res = concatIfMonoid(res.value);
}
res = yield res;
if (done) {
return concatIO.run(context);
}
}
}
// ************************************
function concatIfMonoid(v) {
if (isMonoid(v)) {
concatIO = concatIO.concat(IO.of(v));
return IO.of();
}
else {
return IO.of(v);
}
}
};
}
else if (Nothing.is(res.value)) {
return IO.of("");
}
This line needs to be generalized from using ""
as the empty monoid value to having such a value parameterized to buildRunner(..)
.
This is a fancy, reactive string builder. It's used to define "components" as do-routines that yield string(s) which are all concated together to produce a chunk of HTML, which can then be shoved into the DOM. Since it's based on IOx, it can be set as dependent on other IOs/IOxs as inputs and reactively re-rendered on each update.
Example for how to use the utility:
And here's the candidate first implementation of
doRender(..)
: