Делать что-то бессмысленное в Рамде - PullRequest
0 голосов
/ 29 июня 2018

Я изучаю библиотеку JS Ramda прямо сейчас. И, кажется, есть шаблон, который я не могу исправить правильно. Например, у меня есть этот код.

const filterPayments = filter => payments =>
  r.filter(
    r.allPass([
      typePred(filter),
      amountPred(filter),
      accountPred(filter),
      currencyPred(filter)
    ]),
    payments
  );

Теперь, похоже, это тот случай, когда я не так уж далек от того, чтобы быть способным сделать это совершенно бесплатно. Я просто не могу найти правильный путь.

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

const amountPred = filter => p =>
  r.and(p.betrag >= filter.amount.min, p.betrag <= filter.amount.max);

Может быть, кто-то может указать мне правильное направление или предложить какое-нибудь руководство?

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

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

Он сделал много того, что я сделал бы, и, вероятно, лучше, чем я. И, конечно, он заканчивается с подобным советом. Я всегда стараюсь предположить, что люди не делают фетиш из бессмысленного. Используйте его, когда он сделает ваш код чище и понятнее. Не используйте его, когда это не так.

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

const filterPayments = pipe(
  juxt([typePred, amountPred, accountPred, currencyPred]),
  allPass,
  filter
)

Хотя это довольно чисто, я не думаю, что оно читается так же хорошо, как ваш оригинал, и поэтому я бы не рекомендовал его. Но если вы действительно хотите без очков, это возможно.

0 голосов
/ 30 июня 2018

Совет, который я предлагаю, - придерживаться того, что у вас есть:)

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

Прежде всего, payments появляется в конечной позиции обеих сторон выражения функции, поэтому мы можем просто отбросить это.

const filterPayments = filter =>
  R.filter(
    R.allPass([
      typePred(filter),
      amountPred(filter),
      accountPred(filter),
      currencyPred(filter)
    ]));

Далее мы можем рассмотреть список функций, переданных в R.allPass

R.allPass(R.map(p => p(filter), [typePred, amountPred, accountPred, currencyPred]))

Теперь мы можем начать удалять аргумент filter, щелкнув R.map, чтобы подтолкнуть его к концу.

R.allPass(R.flip(R.map)([typePred, amountPred, accountPred, currencyPred])(p => p(filter))

Теперь давайте сделаем filter и аргумент p => p(filter) вместо того, чтобы закрывать его, делая это:

R.allPass(R.flip(R.map)
  ([typePred, amountPred, accountPred, currencyPred])
  (R.applyTo(filter)))

Теперь он начинает обретать форму, подобную h(g(f(a))), которую мы можем преобразовать в бессмысленную, используя R.pipe, R.compose, R.o и т. Д.

const filterPayments = R.compose(
  R.filter,
  R.allPass,
  R.flip(R.map)([typePred, amountPred__, accountPred, currencyPred]),
  R.unary(R.applyTo) // R.unary is needed here to tell Ramda only to expect the first argument in this composition
)

Это дает нам функцию, которая теперь должна быть эквивалентна вашей filterPayments в бессчетной форме.

Ваш amountPred пример становится еще более запутанным, и я думаю, вы потом согласитесь, что то, что у вас уже есть, - гораздо лучший выбор между этими двумя.

Опять же, мы начинаем с того, что пытаемся вставить аргументы в конец каждой стороны выражения:

filter => p =>
  both(
    x => x >= filter.amount.min,
    x => x <= filter.amount.max
  )(p.betrag)

И тогда мы можем сбросить p:

filter => R.o(
  both(
    x => x >= filter.amount.min,
    x => x <= filter.amount.max
  ),
  prop('betrag'))

Функции, переданные в both, также могут быть заменены:

filter => R.o(
  both(
    R.flip(R.gte)(filter.amount.min),
    R.flip(R.lte)(filter.amount.max)
  ),
  prop('betrag'))

Теперь, чтобы заняться filter, мы можем использовать R.converge, чтобы передать один и тот же аргумент нескольким функциям, а затем объединить результаты каждой из них вместе.

filter => R.o(
  R.converge(both, [
    f => R.flip(R.gte)(R.path(['amount', 'min'], f),
    f => R.flip(R.lte)(R.path(['amount', 'max'], f)
  ])(filter),
  prop('betrag'))

А теперь f находится в конечной позиции, поэтому его можно отбросить композицией:

filter => R.o(
  R.converge(both, [
    R.o(R.flip(R.gte), R.path(['amount', 'min'])),
    R.o(R.flip(R.lte), R.path(['amount', 'max']))
  ])(filter),
  prop('betrag'))

Получение filter до конца - это то, где это становится довольно запутанным, включая переключение функций композиции.

filter => R.o(
  R.flip(R.o)(R.prop('betrag')),
  R.converge(both, [
    R.o(R.flip(R.gte), R.path(['amount', 'min'])),
    R.o(R.flip(R.lte), R.path(['amount', 'max']))
  ])
)(filter)

И наконец ...

const amountPred = R.o(
  R.flip(R.o)(R.prop('betrag')),
  R.converge(both, [
    R.o(R.flip(R.gte), R.path(['amount', 'min'])),
    R.o(R.flip(R.lte), R.path(['amount', 'max']))
  ])
)

... сравнивая это с вашим оригиналом, я знаю, что предпочитаю читать:

const amountPred = filter => p =>
  p.betrag >= filter.amount.min && p.betrag <= filter.amount.max
...