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之类的原子元素的组成。

它的打破和重建很困难:干净利索要求重新排列论据的灵活性,方便性和清晰度(甚至相对于上文中我列出的英文版,因为我首先给出'第三'号码) 。争论和片段重新排序在我看来就是你缺少的东西。

相关问题