函数式编程的技巧

函数式编程的技巧_第1张图片

14.1.2 科里化

给出科里化的理论定义之前,让我们先来看一个例子。应用程序通常都会有国际化的需求将一套单位转换到另一套单位是经常碰到的问题。

单位转换通常都会涉及转换因子以及基线调整因子的问题。比如,将摄氏度转换到华氏度的公式是CtoF(x)=x*9/5 +32。

所有的单位转换几乎都遵守下面这种模式:(1)乘以转换因子

(2)如果需要,进行基线调整

你可以使用下面这段通用代码表达这一模式:

static double converter(double x,double f,double b){return x*f+bi

这里x是你希望转换的数量,是转换因子,b是基线值。但是这个方法有些过于宽泛了。通常,你还需要在同一类单位之间进行转换,比如公里和英里。当然,你也可以在每次调用converter方法时都使用3个参数,但是每次都提供转换因子和基准比较繁琐,并且你还极有可

能输人错误。当然,你也可以为每一个应用编写一个新方法,不过这样就无法对底层的逻辑进行复用。这里我们提供一种简单的解法,它既能充分利用已有的逻辑,又能让converter针对每个应用进行定制。你可以定义一个“工厂”方法,它生产带一个参数的转换方法,我们希望借此来说明科里化。下面是这段代码:

static DoubleUnaryOperator curriedConverter(double f, double b){return (double x)->x*f + b;

现在,你要做的只是向它传递转换因子和基准值(和b),它会不辞辛劳地按照你的要求返回一个方法(使用参数x)。比如,你现在可以按照你的需求使用工厂方法产生你需要的任何Converter:

现在,你要做的只是向它传递转换因子和基准值(和b),它会不辞辛劳地按照你的要求返回一个方法(使用参数x)。比如,你现在可以按照你的需求使用工厂方法产生你需要的任何
converter:
 

DoubleUnaryOperator convertCtoF= curriedConverter(9.0/5,32);DoubleUnaryOperator convertUSDtoGBP = curriedConverter(0.6,0);DoubleUnaryOperatorconvertKmtoMi=curriedConverter(0.6214.0);
由于DoubleUnaryoperator定义了方法applyAsDouble,你可以像下面这样使用你的
converter:
double gbp =convertUsDtoGBP.applyAsDouble(1000);


这样一来,你的代码就更加灵活了,同时它又复用了现有的转换逻辑!让我们一起回顾下你都做了哪些工作。你并没有一次性地向converter方法传递所有的参数x、和b,相反,你只是使用了参数和b并返回了另一个方法,这个方法会接收参数x,最终返回你期望的值x*f+b。通过这种方式,你复用了现有的转换逻辑,同时又为不同的转换因子创建了不同的转换方法。

14.2.1 破坏式更新和函数式更新的比较


让我们看看不这么做会导致怎样的结果。假设你需要使用一个可变类rainJourney(利用一个简单的单向链接列表实现)表示从A地到B地的火车旅行,你使用了一个整型字段对旅程的一些细节进行建模,比如当前路途段的价格。旅途中你需要换乘火车,所以需要使用几个由onwara字段串联在一起的TrainJourney对象;直达火车或者旅途最后一段对象的onward字段为nu11:

class TrainJourneypublic int price;public TrainJourney onward;public TrainJourney(int p,TrainJourneyt){price =Pionward =ti


假设你有几个相互分隔的+rainJourney对象分别代表从X到Y和从Y到Z的旅行。你希望创建一段新的旅行,它能将两个TrainJourney对象串接起来(即从X到Y再到Z)。一种方式是采用简单的传统命令式的方法将这些火车旅行对象链接起来,代码如下:

static TrainJourney link(TrainJourney a,Traindourney b){if (a==null)return biTrainJourney taiwhile(t.onward != nu1l){t = t.onward:
t.onward =bi
return a


这个方法是这样工作的,它找到™rainJourney对象a的下一站,将其由表示a列表结束的nu11替换为列表b(如果a不包含任何元素,你需要进行特殊处理)。这就出现了一个问题:假设变量firstJourney包含了从X地到Y地的线路,另一个变量secondJourney包含了从Y地到Z地的线路,如果你调用1ink(firstJourney,secondJourney方法,这段代码会破坏性地更新firstJourney,结果secondJourney也会加被入到firstJourney,最终请求从X地到Z地的用户会如其所愿地看到整合之后的旅程,不过从X地到Y的京科H被建区州曲再就元上期函数式编程的技巧_第2张图片
 

你可能感兴趣的:(java,开发语言)