Как создать чисто функциональную специальную полиморфную линзу без какого-либо самоанализа?
Я адаптировал реализацию линз DrBoolean, чтобы она работала без самоанализа / набирания утки / опоры на идентичность прототипа. Вычисления должны определяться исключительно продолжениями и аргументами функций функций более высокого порядка. Я зашел так далеко:
const id = x => x;
// compose n functions (right to left)
const $$ = (f, ...fs) => x =>
fs.length === 0
? f(x)
: f($$(...fs) (x));
// function encoded Const type
const Const = x => k => k(x);
const constMap = f => fx => fx(x => Const(x));
const runConst = fx => fx(id);
// lens constructor
const objLens = k => cons => o =>
constMap(v => Object.assign({}, o, {[k]: v})) (cons(o[k]));
const arrLens = i => cons => xs =>
constMap(v => Object.assign([], xs, {[i]: v})) (cons(xs[i]));
const view = fx =>
$$(runConst, fx(Const));
const user = {name: "Bob", addresses: [
{street: '99 Maple', zip: 94004, type: 'home'},
{street: '2000 Sunset Blvd', zip: 90069, type: 'work'}]};
// a lens
const sndStreetLens =
$$(objLens("addresses"), arrLens(1), objLens("street"));
console.log(
view(sndStreetLens) (user) // 2000 Sunset Blvd
);
В этой версии ограничение функтора constMap
жестко запрограммирован в конструкторе линз. когда view
вызывает объектив правильного типа ($$(runConst, fx(Const))
) уже пройден, но для того, чтобы получить специальную полиморфную линзу, мне нужно также передать соответствующий экземпляр функтора.
Я уже попробовал самое очевидное $$(runConst, fx(constMap) (Const))
Однако это мешает композиции. Я просто не могу понять это.