Ramda. js труба, которая устанавливает свойство на основе предыдущего параметра - PullRequest
3 голосов
/ 16 января 2020

В настоящее время у меня есть следующий код (который работает):

const double = R.multiply(2);

const piped = R.pipe(
  (obj) => R.assoc('b', double(obj.a))(obj),
  (obj) => R.assoc('c', double(obj.b))(obj)
);

console.log(
  piped({ a: 1 })
);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Однако я думаю, что из-за того, что (obj) в конце каждой функции конвейера, я думаю, что я мог бы изменить ее на что-то лучшее в "Рамде" Мир".

Я все еще новичок в этой библиотеке, поэтому еще не знаю всех методов и приемов.

Есть ли лучший способ сделать это с помощью Ramda?

Мой "настоящий" код такой:

function getScripts() {
  const tryRequire = tryCatch((path) => require(path).run, always(null));

  const addPathAndRunProps = pipe(
    // Note: The `scriptsPath` function is a bound path.join function.
    // It just returns a string.
    (dir) => assoc('path', scriptsPath(dir.name, 'index.js'))(dir),
    (dir) => assoc('run', tryRequire(dir.path))(dir)
  );

  const addModuleRunAndFilterInvalid = pipe(
    map(addPathAndRunProps),
    filter((dir) => typeof dir.run === 'function')
  );

  return addModuleRunAndFilterInvalid(
    fs.readdirSync(SCRIPTS_PATH, { withFileTypes: true })
  );
}

Ответы [ 2 ]

1 голос
/ 16 января 2020

Я согласен с ответом Калли - возможно, нет веской причины пытаться использовать функции Рамды здесь.

Но, если вам интересно, есть некоторые функции Рамды, которые вы можете использовать .

chain и ap являются довольно обобщенными c функциями, работающими на двух разных абстрактных типах . Но при использовании с функциями они имеют довольно полезное поведение в качестве комбинаторов:

chain (f, g) (x) //=> f (g (x)) (x)
ap (f, g) (x)    //=> f (x) (g (x))

Это означает, что вы можете написать свою функцию следующим образом:

const piped = R.pipe(
  chain (assoc ('b'), pipe (prop ('a'), double)),
  chain (assoc ('c'), pipe (prop ('b'), double)),
)

Я не думаю, что это версия улучшается по оригиналу; повторение этих внутренних вызовов pipe слишком сложное.

Однако с помощью вспомогательной функции это может быть более разумным:

const doubleProp = curry (pipe (prop, double))
// or doubleProp = (prop) => (obj) => 2 * obj[prop]

const piped = R.pipe(
  chain (assoc ('b'), doubleProp ('a')),
  chain (assoc ('c'), doubleProp ('b')),
);

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

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


Кстати, я просто хочу отметить, что я впечатлен качеством вашего вопроса. Очень приятно читать хорошо продуманные и хорошо продуманные вопросы. Спасибо!

1 голос
/ 16 января 2020

Я думаю, вы могли бы чрезмерно использовать Рамду здесь. Код немного сбивает с толку. Скорее всего, в будущем это будет легче читать и поддерживать, хотя он еще будет функционировать:

function getScripts() {
  const tryRequire = tryCatch((path) => require(path).run, always(null));

  const addPathAndRunProps = dir => {
    const path = scriptsPath(dir.name, 'index.js')

     return {
        ...dir,
        path,
        run: tryRequire(path),
     }
  }

  return pipe(
     map(addPathAndRunProps),
     filter(x => typeof x.run === 'function'),
  )(fs.readdirSync(SCRIPTS_PATH, { withFileTypes: true }))
}

Или, если вы действительно хотите сохранить эти установщики, попробуйте разделить вашу функцию addPathAndRunProps на два установщика:

function getScripts() {
  const tryRequire = tryCatch((path) => require(path).run, always(null));

  const addPathProp = x => assoc('path', scriptsPath(x.name, 'index.js'), x)
  const addRunProp = x => assoc('run', tryRequire(x.path), x)

  return pipe(
    map(addPathProp),
    map(addRunProp),
    filter(x => typeof x.run === 'function'),
  )(fs.readdirSync(SCRIPTS_PATH, { withFileTypes: true }))
}

В обоих случаях я избавился от вашей функции addModuleRunAndFilterInvalid. Ваша функция не добавляет ясности, чтобы разделить addModuleRunAndFilterInvalid на ее собственную функцию, а возвращение результата конвейера проясняет назначение самой функции getScripts.

Кроме того, в вашем код, вы продолжаете вызывать объект, на котором вы работаете dir. Это сбивает с толку, поскольку подразумевает, что объект имеет одинаковую структуру при каждом вызове функции. Однако переменная, переданная в addRunProp, не имеет той же структуры, что и переменная, переданная в addPathProp (для переменной, переданной в addRunProp, требуется дополнительная path prop). Либо придумайте описательное имя, либо просто используйте x. Вы можете думать о x как о том, над чем работает ваша функция. Чтобы выяснить, что такое x, посмотрите на имя функции (например, addRunProp означает, что к x добавлено свойство run).

Еще один потенциально полезный совет: I Мы установили соглашение о присвоении имен aug (сокращенно от "augment") для добавления свойства или части информации к объекту. Поэтому я переименую вашу addPathProp функцию augPath и переименую вашу addRunProp функцию augRun. Поскольку я использую его последовательно, я знаю, что когда я вижу aug в начале функции, он добавляет свойство.

...