Бессмысленная композиция линз в Ramda.js - PullRequest
0 голосов
/ 15 января 2019

Я пытаюсь составить функции, которые возвращают линзы, создать новую линзу и сделать это в бессмысленном стиле.

Вероятно, это более общий вопрос о композиции функций. Линзы - это просто пример. Меня не интересуют объективы, но я хочу узнать общую схему, как составлять эти функции бессмысленно.

const obj = {a: {x: 0}, b: {x: 42}};

// this won't work, but I want it to work
const pointFreeComposedLens = R.compose(R.lensProp, R.lensProp('x'));
R.view(pointFreeComposedLens('a'), obj); // returns 'undefined'

// this works
const pointyComposedLens = key => R.compose(R.lensProp(key), R.lensProp('x'));
R.view(pointyComposedLens('a'), obj); // returns '0'

Каков шаблон для составления функций, чтобы мне не нужно было переписывать аргументы для первой функции в конвейере композиции?

Для вопиющего примера:

const deepLens = (a, b, c) => R.lensPath([a, b, c]);

// This works, but is tedious & verbose
const extraDeep = (a, b, c, x) => R.compose(deepLens(a,b,c), R.lensProp(x));
const gammaDeep = (a, b, c, y) => R.compose(deepLens(a,b,c), R.lensProp(y));

// Doesn't work, but it would be nicer to write:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));

// and call it like so:
R.view(extraDeep('a','b','c','x'), obj);

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Если вы намереваетесь написать функцию, которая принимает путь и объект, тогда path уже существует:

R.path(['a', 'b'], {a: {b: 10}}); //=> 10

Если вы заинтересованы в удалении некоторых параметров в некоторых из ваших функций, deepLens можно переписать следующим образом:

const deepLens = R.unapply(R.lensPath);

Эта бессмысленная версия имеет дополнительное преимущество, заключающееся в том, что она не ограничивается тремя параметрами. Он будет работать с любым количеством параметров:

deepLens('a', 'b');           //=> R.lensPath(['a', 'b']);
deepLens('a', 'b', 'c');      //=> R.lensPath(['a', 'b', 'c']);
deepLens('a', 'b', 'c', 'd'); //=> R.lensPath(['a', 'b', 'c', 'd']);
0 голосов
/ 15 января 2019

Я знаю, что вы смотрите на линзы только в качестве примера, но вот один из способов получить что-то похожее на поведение, которое, я думаю, вы хотите от них.

const {lensPath, compose, lens, view} = R

const deepLens = (a, b, c) => lensPath([a, b, c]);
const deeper = (lens, ...args) => compose(lens, lensPath(args))

const cLens = deepLens('a', 'b', 'c')
const obj =  {a: {b: { c: {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}}}}

console.log(view(cLens, obj)) //=> {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}
console.log(view(deeper(cLens, 'f', 'g'), obj)) //=> 3

const fLens = deeper(cLens, 'f')

console.log(view (fLens, obj)) //=> {g: 3, h: 4, i: {j: 5, k: 6}}

const jLens = deeper(cLens, 'f', 'i', 'j')
// or jLens = deeper(fLens, 'i', 'j')

console.log(view(jLens, obj)) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Что касается более широкого вопроса о композиции, линзы, как правило, являются особым случаем для такой библиотеки, как Ramda, поскольку композиция находится в порядке, противоположном, как обычно и ожидается. (Здесь слишком много технических причин.)

Но вот почему это не работает:

const extraDeep = x => R.compose(deepLens, R.lensProp(x));

Рамда разрешает первой функции в цепочке композиции (крайняя справа в compose, крайняя слева в pipe получать дополнительные аргументы. Но когда порядок компоновки изменяется с помощью линзовой композиции, она не делает то, что вам может понравиться .

Так что, если у вас есть похожие проблемы с композицией в другом контексте, пожалуйста, откройте отдельный вопрос. Мне было бы интересно посмотреть, что вы ищете.

0 голосов
/ 15 января 2019

Параметры остальных сокращают код до:

 const extraDeep = (...rest) => last => R.compose(deepLens(...rest), R.lensProp(last))(rest.pop());

но я не уверен, что это действительно элегантно.

...