2017-10-15 3 views
2

J'essaie d'apprendre à utiliser les foncteurs applicatifs en javascript et suis tombé sur la méthode ap. Je suis en train de l'utiliser pour combiner trois tableaux comme ceci:Quel est mon foncteur applicatif ne fonctionnant pas avec l'ap de Ramda?

const products = ['teeshirt', 'sweater'] 
const options = ['large', 'medium', 'small'] 
const colors = ['red', 'black'] 

Alors que par le documentation Je suis d'essayer ceci:

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

const merchandise = R.ap([buildMerch], [products, options, colors]) 

Mais cela me redonne trois fonctions:

[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; 
    }; 
}] 

... au lieu du résultat combiné des tableaux que j'attends:

["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"] 

Qu'est-ce que je fais mal? Comment puis-je réparer ça?

Voici un jsbin la question: https://jsbin.com/fohuriy/14/edit?js,console

Répondre

3

ap applique une liste des fonctions à une liste de valeurs, par la documentation. Votre fonction buildMerch a le "type" suivante:

buildMerch :: String -> String -> String -> String 

Le genre de ap plus simple est map: pour tout foncteur applicatif, nous obtenons:

pure f <*> a 
    ====== 
map f a 

Pour les tableaux, pure est x => [x]. Ainsi,

R.ap([buildMerch], [foo, bar, baz]) 
    ====== 
R.map(buildMerch, [foo, bar, baz]) 

En cartographiant buildMerch sur la liste des arguments, nous sommes en partie l'appliquer aux tableaux en question. L'expression qui fait ce que vous voulez est:

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

D'abord, nous Carte buildMerch sur le réseau de produits. Cela nous donne un tableau de fonctions prenant deux arguments: [String -> String -> String]. Ensuite, nous utilisons R.ap pour combiner cela avec options :: [String], qui applique chaque fonction dans le premier tableau avec chaque argument dans le tableau options. Maintenant, nous avons [String -> String], et enfin nous R.ap cela avec colors pour obtenir le tableau final des chaînes que vous voulez.

+2

bonne explication, je vous remercie! –

1

AP applique une liste de fonctions à une liste de valeurs. Dans votre cas, vous appelez buildMerch avec chaque élément de votre tableau spécifié, qui est products, puis options et ensuite avec colors, et non avec toutes les combinaisons au sein de vos baies. Cela ne correspond pas à la signature de votre méthode, où vous attendez trois arguments.

1

Une autre façon de résoudre ce problème consiste à ajouter ap au tableau javascript natif. De cette façon, vous transformez essentiellement Array en un foncteur applicatif, vous n'avez pas besoin d'une bibliothèque, et cela fonctionne avec la même interface que n'importe quel autre foncteur applicatif que vous voudrez utiliser.

// add ap 
Array.prototype.ap = function(anotherArray) { 
    return this.map(el => 
    anotherArray.map(el) 
).flatten(); 
}; 

Ceci repose sur aplatir (ou «joindre»).

// add flatten 
Array.prototype.flatten = function() { 
    let results = []; 
    this.forEach(subArray => { 
    subArray.forEach(item => { 
     results.push(item); 
    }); 
    }); 
    return results; 
}; 

maintenant:

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); 

Maintenant, vous pouvez également lever toutes les trois:

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

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