【问题标题】:Ramda: Remember and use valueRamda:记住并使用价值
【发布时间】:2020-10-06 23:51:22
【问题描述】:

我正在尝试“Ramdafy”一个函数并使其无点。这是我走了多远:

const hasFetchedForFilterQueryString = state => {
  const filterQueryString = getFilterQueryString(state);
  return either(
    pipe(getPages, has(filterQueryString)),
    pipe(getNewlyLoadedUsers, has(filterQueryString)),
  )(state);
};

// or

const hasFetchedForFilterQueryString = state =>
  either(
    pipe(getPages, has(getFilterQueryString(state))),
    pipe(getNewlyLoadedUsers, has(getFilterQueryString(state))),
  )(state);

我想知道是否有一种方法可以编写更多的无点数,因此无需将filterQueryString 保存在变量中并且不必手动应用state

【问题讨论】:

  • 总有办法让它变得无意义,但在这种情况下它是毫无意义的。
  • 请注意,例如,monad 被设计为函数应用程序(非无点),而不是 kleisli 组合,也就是说,无点不一定更具功能性。
  • @Bergi:我通常同意,但在这里我认为我们可以制作一个非常有用的无点版本。看我的回答。

标签: javascript functional-programming ramda.js pointfree


【解决方案1】:

我通常同意 Bergi 的评论。无点不应该是一个目标。当我开始编写 Ramda 时,我就迷上了它,其中有许多功能旨在帮助使事情变得无意义。我很少再推荐他们了。我不认为useWithconverge 通常会使函数更易于阅读或维护。

但是有一个函数,lift,在 FP 世界中广为人知,在这里很有帮助。我认为lift 将功能从价值领域提升到这些价值的容器领域。因此lift (add) (Maybe(3), Maybe(5)) //=> Maybe(8)。当与产生我们的值的函数一起使用时,它可能会像这样工作:

lift ((a, b) => a + b) (
  n => n * 2, 
  n => n - 1
) (5) 
//=> (5 * 2) + (5 -1) //=> 14`.

这正是你想要对你的函数做的事情。所以这里有一个基于lift的免积分版本:

const hfffqs2 = either (
  lift (has) (getFilterQueryString, getPages),
  lift (has) (getFilterQueryString, getNewlyLoadedUsers)
)

我发现这比您上面的任何一个版本都更具可读性。

我认为该版本可与我能想到的最简单的非 Ramda 版本相媲美:

const hfffqs3 = state => {
  const query = getFilterQueryString(state);
  return query in getPages(state)
      || query in getNewlyLoadedUsers(state)
}

不过,它不一定更多可读。而且它的效率较低——除了额外的函数调用——它必须调用getFilterQueryString 两次。但它是一个可读和可维护的功能。

如果lift 还不是很清楚,中间格式可能如下所示:

const hfffqs1 = either (
  state => has(getFilterQueryString(state), getPages(state)),
  state => has(getFilterQueryString(state), getNewlyLoadedUsers(state))
)

通过将getFilterQueryStringgetState 应用于lift (has),我们得到state => has(getFilterQueryString(state), getPages(state)) 的等价物,下一行也类似。我们已经提升函数has从字符串和对象领域到返回字符串和对象的函数。我们可以将state传递给这两个函数,得到一个字符串和一个对象。


您可以在以下 sn-p 中看到这些操作:

// Dummy implementations just for demo.  `state` is a small integer.
const getFilterQueryString = (state) => ['foo', 'bar', 'baz', 'qux', 'corge', 'grault'][state]
const getPages = (state) => [{foo: 1, bar: 2}, {foo: 1, corge: 2, grault: 3}, {baz: 1}, {foo: 1, grault: 2}, {corge: 1, baz: 2}, {bar: 1, qux: 2}][state]
const getNewlyLoadedUsers = (state) => [{baz: 1, qux: 2}, {corge: 1, grault: 2}, {foo: 1, corge: 2}, {baz: 1, qux: 2}, {foo: 1, qux: 2}, {bar: 1, corge: 2}][state]

const hasFetchedForFilterQueryString = state => {
  const filterQueryString = getFilterQueryString(state);
  return either(
    pipe(getPages, has(filterQueryString)),
    pipe(getNewlyLoadedUsers, has(filterQueryString)),
  )(state);
};

console .log ([0, 1, 2, 3, 4, 5].map(hasFetchedForFilterQueryString))

const hfffqs1 = either (
  state => has(getFilterQueryString(state), getPages(state)),
  state => has(getFilterQueryString(state), getNewlyLoadedUsers(state))
)

console .log ([0, 1, 2, 3, 4, 5].map(hfffqs1))

const hfffqs2 = either (
  lift (has) (getFilterQueryString, getPages),
  lift (has) (getFilterQueryString, getNewlyLoadedUsers)
)

console .log ([0, 1, 2, 3, 4, 5].map(hfffqs2))

const hfffqs3 = state => {
  const query = getFilterQueryString(state);
  return query in getPages(state)
      || query in getNewlyLoadedUsers(state)
}

console .log ([0, 1, 2, 3, 4, 5].map(hfffqs3))
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {either, pipe, has, lift} = R                         </script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2011-07-28
    • 2012-07-10
    相关资源
    最近更新 更多