Ramda - 部分应用功能取决于完整应用

时间:2018-02-02 02:34:20

标签: javascript functional-programming ramda.js

我有一种情况,我想要添加的值取决于未来的值,即

let metadata = {videoId: 123, likes: 400};
let addSubtitles = R.assoc('subtitles', R.__, R.__);

此处addSubtitles是部分应用的功能。但是,addSubtitles的第二个参数应该是字幕,但字幕本身依赖于第三个参数,即metadata.videoId。如下调用:

addSubtitles(metadata); //but with another argument perhaps?
const subtitles = async getSubtitles(videoId) => await apiCall(videoId);

以功能方式解决这个问题的方法是什么?似乎我可以约束未来第三个论点的背景,但不确定如何去做这个。

如果有任何额外信息需要回答,请告诉我。

这是一个有效的解决方案,但我希望使用Ramda来完成这项工作:

const addSubs = async function(el) {¬
  const subtitles = await writeCaptions(el.videoId);¬
  return R.assoc('subtitles', subtitles, el);¬
};

1 个答案:

答案 0 :(得分:2)

首先让我补充一下,注意您不需要在签名中使用R._来获取以后的值。几乎Ramda库中的每个函数都是自动调用的,因此您可以调用所有参数或仅使用某个子集来预加载数据。 R._仅用于为将来的呼叫保留空间。

所以你想要做的就是只要一次添加一个参数,直到你得到一个完整的函数准备好调用。如果订单有误,您可以使用R.flipR._(取决于具体情况)来达到您准备填写的价值,然后回到您还不知道的价值。< / p>

因此,根据您的描述,您可能会担心getSubtitles(metadata)是一个返回承诺的网络调用。这个例子将在这个假设下进行。在这里,我认为R.flipR._更具表现力。

const  metadata = { videoId: 123, likes: 400 }

const addSubtitles = R.flip(R.assoc('subtitles'))
// Now you have a curried function that takes 2 arguments, first the metadata, and then the subtitles.

const withSubtitlesPromise = getSubtitles(metadata)
  // Here we drill down a little further by adding the metadata, and then
  // pass it as the callback to .then, which will pass in the final param
  // once it resolves
  .then(addSubtitles(metadata)

withSubtitlesPromise.then(console.log)

您绝对可以在单个函数中捕获所有这些逻辑,该函数接收metadata并返回字幕数据的承诺。为了更好地衡量,我们还将getSubtitles作为依赖性传递,以便于测试和更弱的耦合。现在,换掉另一个用于检索字幕数据的功能是微不足道的。在这种情况下,使用R._会使代码更清晰,因此我们会将其切换。

// Define all the logic in a single easy function
const makeAddSubtitles = getSubtitles => metadata =>
  getSubtitles(metadata).then(R.assoc('subtitles', R._, metadata))

// Then push in the dependency
const addSubtitles = makeAddSubtitles(getSubtitles)

// Use it
const vid123 = { videoId: 123, likes: 400 }
const vid123WithSubsPromise = addSubtitles(vid123)