2017-10-15 79 views
2

我想學習如何在JavaScript中使用應用函子,並遇到了ap方法。我想用它來三個陣列相結合,像這樣:我的應用函子不適用於Ramda的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

回答

3

ap每個文檔應用的功能清單,值的列表。你的功能buildMerch具有以下 「類型」:

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

最簡單的那種apmap:對於任何適用函子,我們得到:

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

對於數組,purex => [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.apoptions :: [String]options :: [String]合併,該函數將第一個數組中的每個函數與options數組中的每個參數一起應用。現在我們有[String -> String],最後我們R.apcolors得到你想要的最終的字符串數組。

+2

很好的解釋,謝謝! –

1

AP將函數列表應用於值列表。在你的情況下,你將調用buildMerch與指定數組中的每個元素,即products,然後options,然後是colors,而不是數組中的每個組合。這與您的方法簽名不匹配,您希望有三個參數。

1

解決此問題的另一種方法是將ap添加到原生javascript Array。這樣,你基本上把Array變成了一個應用函數,你不需要一個庫,它可以和你可能想要使用的其他應用函數一樣使用相同的接口。

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

這依賴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 
相關問題