0

我想寫一個函數,比較使用另一個函數的兩個項目,然後檢查結果是否大於也提供給該函數的其他值。我可以這樣寫:有沒有辦法在不列出參數的情況下編寫這個Javascript函數?

const compareDifference = function(t1, t2, threshold) { 
    return getDifference(t1, t2) > threshold; 
}; 

...但這似乎不太有用。我覺得古典組成中的每例假定我就知道要針對比較的值稱爲函數之前,在這種情況下,我可以把它寫功能就像這樣:

const greaterThan = (x, y) => x > y; 
const greaterThan10 = _.partial(greaterThan, _, 10); 
const compareDifference = _.compose(greaterThan10, getDifference); 

因爲我是比較新的函數式編程,我覺得我在這裏錯過了一些簡單或基本的東西。有沒有一種方法可以編寫函數,以便將參數傳遞給greaterThan,而不必明確提及它?理想情況下是這樣的:

const compareDifference = _.compose(_.partial(greaterThan, _), getDifference); 
+0

你能解釋一下到底如何你」你喜歡用你的功能嗎? – Amit

+0

我想用所有三個參數一次調用它,因爲我可以使用頂部的原始版本。所以:compareDifference(item1,item2,10); –

+0

「*這似乎不是很有用*」 - 它絕對沒有錯。 – Bergi

回答

3

我認爲LUH3417的答案對初學者很好。它涉及到一些基本知識,但我認爲有一些其他信息的空間

首先,如果您想在原始問題中使用完全相同的API,可以將其分解爲如下部分。

const comp = f=> g=> x=> f (g (x)) 
 
const comp2 = comp (comp) (comp) 
 
const flip = f=> x=> y=> f (y) (x) 
 
const sub = x=> y=> y - x 
 
const abs = x=> Math.abs 
 
const diff = comp2 (Math.abs) (sub) 
 
const gt = x=> y=> y > x 
 

 
// your function ... 
 
// compose greaterThan with difference 
 
// compareDifference :: Number -> Number -> Number -> bool 
 
const compareDifference = comp2 (flip(gt)) (diff) 
 

 
console.log(compareDifference (3) (1) (10)) 
 
// = gt (10) (abs (sub (1) (3))) 
 
// = Math.abs(1 - 3) > 10 
 
// => false 
 

 
console.log(compareDifference (5) (17) (10)) 
 
// = gt (10) (abs (sub (5) (17))) 
 
// = Math.abs(17 - 5) > 10 
 
// => true

但是,你是對有懷疑,你原來的代碼不覺得功能。我在這裏給你的代碼工作,但它仍然感覺... off,對吧?我認爲如果你將它作爲一個higher-order function,也就是接受一個函數作爲參數(和/或返回一個函數)的函數,會大大改善你的函數。


黃磚路

然後我們可以創建一個名爲testDifference一個通用的函數,它接受一個閾值函數t輸入和2數字立足於閾值計算

// testDifference :: (Number -> bool) -> Number -> Number -> bool 
const testDifference = t=> comp2 (t) (diff) 

看一下實現,這是有道理的。到測試差異,我們需要測試(某些功能),我們需要兩個數字來計算的差異

下面是使用它

testDifference (gt(10)) (1) (3) 
// = gt (10) (abs (sub (1) (3))) 
// = Math.abs(1 - 3) > 10 
// = Math.abs(-2) > 10 
// = 2 > 10 
// => false 

這是一個很大的進步,因爲>(或gt)不再是你的函數硬編碼的例子。這使得它更多才多藝。你看,我們可以很容易地與lt

const lt = x=> y=> y < x 

testDifference (lt(4)) (6) (5) 
// = lt (4) (abs (sub (6) (5))) 
// = Math.abs(5 - 6) < 4 
// = Math.abs(-1) < 4 
// = 1 < 4 
// => true 

使用它,或者讓我們定義一個真正嚴格的門檻,強制執行的數字有1

const eq = x=> y=> y === x 
const mustBeOne = eq(1) 

testDifference (mustBeOne) (6) (5) 
// = eq (1) (abs (sub (6) (5))) 
// = Math.abs(5 - 6) === 1 
// = Math.abs(-1) === 1 
// = 1 === 1 
// => true 

testDifference (mustBeOne) (5) (8) 
// = eq (1) (abs (sub (5) (8))) 
// = Math.abs(8 - 5) === 1 
// = Math.abs(3) === 1 
// = 3 === 1 
// => false 

因爲testDifference是令行禁止一個確切的區別,你也可以將其用作部分應用功能

// return true if two numbers are almost the same 
let almostSame = testDifference (lt(0.01)) 

almostSame (5.04) (5.06) 
// = lt (0.01) (abs (sub (5.04) (5.06))) 
// = Math.abs(5.06 - 5.04) < 0.01 
// = Math.abs(0.02) < 0.01 
// = 0.02 < 0.01 
// => false 

almostSame (3.141) (3.14) 
// = lt (0.01) (abs (sub (3.141) (3.14))) 
// = Math.abs(3.14 - 3.141) < 0.01 
// = Math.abs(-0.001) < 0.01 
// = 0.001 < 0.01 
// => true 

總之現在

下面是與testDifference代碼片段中實現,你可以在瀏覽器中運行,看到它的工作

// comp :: (b -> c) -> (a -> b) -> (a -> c) 
 
const comp = f=> g=> x=> f (g (x)) 
 

 
// comp2 :: (c -> d) -> (a -> b -> c) -> (a -> b -> d) 
 
const comp2 = comp (comp) (comp) 
 

 
// sub :: Number -> Number -> Number 
 
const sub = x=> y=> y - x 
 

 
// abs :: Number -> Number 
 
const abs = x=> Math.abs 
 

 
// diff :: Number -> Number -> Number 
 
const diff = comp2 (Math.abs) (sub) 
 

 
// gt :: Number -> Number -> bool 
 
const gt = x=> y=> y > x 
 

 
// lt :: Number -> Number -> bool 
 
const lt = x=> y=> y < x 
 

 
// eq :: a -> a -> bool 
 
const eq = x=> y=> y === x 
 

 
// (Number -> bool) -> Number -> Number -> bool 
 
const testDifference = f=> comp2 (f) (diff) 
 

 
console.log('testDifference gt', testDifference (gt(10)) (1) (3)) 
 
console.log('testDifference lt', testDifference (lt(4)) (6) (5)) 
 
console.log('testDifference eq', testDifference (eq(1)) (6) (5)) 
 

 
// almostSame :: Number -> Number -> bool 
 
let almostSame = testDifference (lt(0.01)) 
 

 
console.log('almostSame', almostSame (5.04) (5.06)) 
 
console.log('almostSame', almostSame (3.141) (3.14))

+0

+1,儘管我寧願命名'threshold'函數'testDifference' - 閾值是第一個參數。 – Bergi

+0

嗨@naomik,這是 - 一如既往 - 一個很好的答案。第二個想法是我已經撤回了我的,因爲它留下了「一些其他信息的空間」,因爲你放得很寬大。 – ftor

+1

@Bergi謝謝你的建議,我喜歡它。我更新了答案。 – naomik

0

如果我找錯了樹本,然後告訴我,我會修改,但如果我想要做這樣的事情,這是「更多功能」我會做到以下幾點:

let greaterThan = _.curry((x, y) => y > x); // notice the args are flipped 
let difference = _.curry((x, y) => Math.abs(x - y)); 
let greaterThan5 = greaterThan(5); // this naming is why we ordered the args backwards 
let differenceBetweenGreaterThan5 = _.compose(greaterThan5, difference); 
differenceBetweenGreaterThan5(10, 34); // true 
differenceBetweenGreaterThan5(10, 6); // false 

然後我們可以改寫原來的功能,像這樣:

let compareDiff = (threshold, x, y) => { 
    return _.compose(greaterThan(threshold), difference)(x)(y); 
}; 

雖然我可能只使用類似differenceBetweenGreaterThan5

另外,我爲漫長的變量名稱表示歉意,但我希望它很清楚我命名的內容。還有其他一些注意事項:我將參數重新排列爲greaterThan以使部分應用程序的命名更明智,並避免需要佔位符_。雖然我對此進行了深入研究,並認爲它適用於通用類型,但對於此示例來說不是必需的。

至於我認爲你錯過了什麼,這種情況下的功能方法(根據我對「功能方法」的含義的理解)是,我們打破了獲取兩個數字之間的差異並查看是否有第三個落入該範圍,將其分解成其原子成分,並將其構成爲諸如greaterThandifference之類的原子元素的組成。

它的打破和重建很困難:乾淨利索要求重新排列論據的靈活性,方便性和清晰度(甚至相對於上文中我列出的英文版,因爲我首先給出'第三'號碼) 。爭論和片段重新排序在我看來就是你缺少的東西。

相關問題