什么是我的应用函子不能与 Ramda 的 ap 一起工作?
What is my applicative functor not working with Ramda's ap?
我正在尝试学习如何在 javascript 中使用应用函子,并遇到了 ap
方法。我正在尝试使用它来组合三个数组,如下所示:
const products = ['teeshirt', 'sweater']
const options = ['large', 'medium', 'small']
const colors = ['red', 'black']
所以根据 documentation 我正在尝试这个:
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:https://jsbin.com/fohuriy/14/edit?js,console
根据文档,ap
将函数列表应用于值列表。您的函数 buildMerch
具有以下 "type":
buildMerch :: String -> String -> String -> String
最简单的 ap
是 map
:对于任何应用函子,我们得到:
pure f <*> a
======
map f a
对于数组,pure
是 x => [x]
。所以,
R.ap([buildMerch], [foo, bar, baz])
======
R.map(buildMerch, [foo, bar, baz])
通过将 buildMerch
映射到参数列表,我们将其部分应用于相关数组。做你想做的表达是:
const merchandise = R.ap(R.ap(R.map(buildMerch, products), options), colors);
首先,我们将 buildMerch
映射到产品数组。这给了我们一个带有两个参数的函数数组:[String -> String -> String]
。然后,我们使用 R.ap
将其与 options :: [String]
组合,后者将第一个数组中的每个函数与 options
数组中的每个参数一起应用。现在我们有 [String -> String]
,最后我们 R.ap
用 colors
得到你想要的最终字符串数组。
AP 将函数列表应用于值列表。在您的情况下,您将对指定数组中的每个元素调用 buildMerch
,即 products
,然后是 options
,然后是 colors
,而不是每个组合你的数组。这与您期望三个参数的方法签名不匹配。
解决这个问题的另一种方法是将ap
添加到原生javascript数组。通过这种方式,您实际上是将 Array 变成了一个应用仿函数,您不需要库,并且它与您可能想要使用的任何其他应用仿函数使用相同的接口。
// add ap
Array.prototype.ap = function(anotherArray) {
return this.map(el =>
anotherArray.map(el)
).flatten();
};
这依赖于展平(或'join')。
// 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
我正在尝试学习如何在 javascript 中使用应用函子,并遇到了 ap
方法。我正在尝试使用它来组合三个数组,如下所示:
const products = ['teeshirt', 'sweater']
const options = ['large', 'medium', 'small']
const colors = ['red', 'black']
所以根据 documentation 我正在尝试这个:
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:https://jsbin.com/fohuriy/14/edit?js,console
ap
将函数列表应用于值列表。您的函数 buildMerch
具有以下 "type":
buildMerch :: String -> String -> String -> String
最简单的 ap
是 map
:对于任何应用函子,我们得到:
pure f <*> a
======
map f a
对于数组,pure
是 x => [x]
。所以,
R.ap([buildMerch], [foo, bar, baz])
======
R.map(buildMerch, [foo, bar, baz])
通过将 buildMerch
映射到参数列表,我们将其部分应用于相关数组。做你想做的表达是:
const merchandise = R.ap(R.ap(R.map(buildMerch, products), options), colors);
首先,我们将 buildMerch
映射到产品数组。这给了我们一个带有两个参数的函数数组:[String -> String -> String]
。然后,我们使用 R.ap
将其与 options :: [String]
组合,后者将第一个数组中的每个函数与 options
数组中的每个参数一起应用。现在我们有 [String -> String]
,最后我们 R.ap
用 colors
得到你想要的最终字符串数组。
AP 将函数列表应用于值列表。在您的情况下,您将对指定数组中的每个元素调用 buildMerch
,即 products
,然后是 options
,然后是 colors
,而不是每个组合你的数组。这与您期望三个参数的方法签名不匹配。
解决这个问题的另一种方法是将ap
添加到原生javascript数组。通过这种方式,您实际上是将 Array 变成了一个应用仿函数,您不需要库,并且它与您可能想要使用的任何其他应用仿函数使用相同的接口。
// add ap
Array.prototype.ap = function(anotherArray) {
return this.map(el =>
anotherArray.map(el)
).flatten();
};
这依赖于展平(或'join')。
// 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