天天看点

泛函编程(10)-异常处理-Either

  上节我们介绍了新的数据类型option:一个专门对付异常情况出现时可以有一致反应所使用的数据类型。option可以使编程人员不必理会出现异常后应该如何处理结果,他只是获得了一个none值,但这个none值与他所期待的类型是一致的,他可以继续用处理这种类型数据的方法使用这个结果。不过遗憾的是我们通过none值只能知道某个计算没能得出结果,但到底发生了什么事option并没有提供任何提示。这样我们也就无法向用户提供贴切的系统错误或着操作失误信息了。

     这样我们就需要在option的基础上添加一个扩展功能的新数据类型,让它可以返回一些异常描述:either。可以想象either在返回none的同时还要包含一个返回值,用来描述异常。那么这个none的形式就变成了none(e)了。我们先看看eigher的框架设计:

以上可见either需要处理两个类型e和a:e代表异常类型,a代表计算类型。与option一样,either也有两种状态:left代表无法完成计算,返回值e是对异常情况的描述、right则代表计算正常完成,返回计算结果a。从英文解释,either不是right就是left。这种情况被称为类型的“不联合性”(disjoint union)。

提出了either的基本描述后开始数据类型操作函数的实现:

还是由于either这种类型的管子里只能存一个元素,所以操作函数的实现比较直接简单:用类型匹配和递归算法就行了。

在以下的函数中我们可以用一个函数 (a,b) => c 把两个either[a],either[b]组合成either[c]:

考虑map2时并不复杂:由于我只有一个利用低阶的函数(a,b) =??? ,我必须想办法把either管子里的那个元素取出来计算完后塞到一个新的either管子里去。以上我们已经实现了map,flatmap我们可以使用for comprehension来实现:

aa <- a: either - 从either管子取出元素

yield 产生新的either。map2_1是for comprehension的直接写法。

由于我们有map和flatmap,我们可以试着用用either:

可以看出在以上三个动作中(age,name,salary)如果其中任何一个出现了异常left,结果就会是left了。

当然,我们还是有可能对一个系列的either类型值进行计算的,所以sequence,traverse这两个函数总是会用到的:

来个实际点的例子:

mkperson输入参数正确时返回right。任何参数错误返回left。不过如果两个参数都是错误的话就只能返回其中一个提示信息了。我们可以修改map2来获取全部信息:

注意:我们必须明确类型e为string,这样才能把两个数据接起来,因为我们不知道如何连接类型e。看看使用新版本后的结果:

没错,两个信息都连接起来返回了。

继续阅读