Javascript 什么是我的应用函子不与Ramda';美联社?

Javascript 什么是我的应用函子不与Ramda';美联社?,javascript,functional-programming,ramda.js,applicative,Javascript,Functional Programming,Ramda.js,Applicative,我试图学习如何在javascript中使用应用程序函子,并遇到了ap方法。我尝试使用它来组合三个阵列,如下所示: const products = ['teeshirt', 'sweater'] const options = ['large', 'medium', 'small'] const colors = ['red', 'black'] 因此,根据我正在尝试的: const buildMerch = product => option => color =>`${p

我试图学习如何在javascript中使用应用程序函子,并遇到了
ap
方法。我尝试使用它来组合三个阵列,如下所示:

const products = ['teeshirt', 'sweater']
const options = ['large', 'medium', 'small']
const colors = ['red', 'black']
因此,根据我正在尝试的:

const buildMerch = product => option => color =>`${product}-${option}-${color}`

const merchandise = R.ap([buildMerch], [products, options, colors])
但这给了我三个功能:

[function (option) {
  return function (color) {
    return product + '-' + option + '-' + color;
  };
}, function (option) {
  return function (color) {
    return product + '-' + option + '-' + color;
  };
}, function (option) {
  return function (color) {
    return product + '-' + option + '-' + color;
  };
}]
…而不是我期望的阵列的组合结果:

["teeshirt- large-red", "teeshirt- large-black", "teeshirt- medium-red", "teeshirt- medium-black", "teeshirt- small-red", "teeshirt- small-black", "sweater- large-red", "sweater- large-black", "sweater- medium-red", "sweater- medium-black", "sweater- small-red", "sweater- small-black"]
我做错了什么?我该如何解决这个问题


下面是一个jsbin,其中有一个问题:

ap
根据文档将函数列表应用于值列表。您的函数
buildMerch
具有以下“类型”:

最简单的
ap
map
:对于任何应用函子,我们得到:

pure f <*> a
  ======
map f a
通过在参数列表上映射
buildMerch
,我们可以部分地将其应用于所讨论的数组。实现所需功能的表达式是:

const merchandise = R.ap(R.ap(R.map(buildMerch, products), options), colors);

首先,我们在产品阵列上映射
buildMerch
。这为我们提供了一个包含两个参数的函数数组:
[String->String->String]
。然后,我们使用
R.ap
将其与
选项组合::[String]
,它将第一个数组中的每个函数应用于
选项
数组中的每个参数。现在我们有了
[String->String]
,最后我们使用
颜色
R.ap
来获得您想要的字符串的最终数组。

将函数列表应用于值列表。在您的情况下,您将使用指定数组中的每个元素调用
buildMerch
,即
products
,然后使用
options
,然后使用
colors
,而不是数组中的每个组合。这与您的方法签名不匹配,您需要三个参数。

解决此问题的另一种方法是将
ap
添加到本机javascript数组中。通过这种方式,您实际上是将数组转化为一个应用程序函子,您不需要库,并且它与您可能想要使用的任何其他应用程序函子使用相同的接口

// add ap
Array.prototype.ap = function(anotherArray) {
  return this.map(el =>
    anotherArray.map(el)
  ).flatten();
};
这依赖于展平(或“连接”)

现在:

现在,您还可以提起所有三个:

const liftA3 = (fn, functor1, functor2, functor3) =>
  functor1.map(fn).ap(functor2).ap(functor3);

liftA3(buildMerch, products, options, colors) // also returns merchandise
// add ap
Array.prototype.ap = function(anotherArray) {
  return this.map(el =>
    anotherArray.map(el)
  ).flatten();
};
// add flatten
Array.prototype.flatten = function() {
  let results = [];
  this.forEach(subArray => {
    subArray.forEach(item => {
      results.push(item);
    });
  });
  return results;
};
const products = ['teeshirt', 'sweater'];
const options = ['large', 'medium', 'small'];
const colors = ['red', 'black'];
const buildMerch = product => option => color =>`${product}-${option}-${color}`;

const merchandise = products.map(buildMerch).ap(options).ap(colors);
const liftA3 = (fn, functor1, functor2, functor3) =>
  functor1.map(fn).ap(functor2).ap(functor3);

liftA3(buildMerch, products, options, colors) // also returns merchandise