麦克西米不可思议--haskell max函数

maximum awesome

maximum取一组可排序的List(属于 Ord类型类)做参数,并返回其中的最大值。想想,在命令式风格下实现这一函数该怎么办。你很可能就会设一个变量来存储当前的最大值,然后用循环遍历该 list,若存在比这个值更大的元素,则修改变量为这一元素的值。到最后,变量的值就是运算结果。唔!描述如此简单的算法还颇费了点口舌呢!

现 在看看递归的思路是如何:我们先定下一个边缘条件,即处理单个元素的List时,返回该元素。如果该List的头部大于尾部的最大值,我们就可以假定较长 的List的最大值就是它的头部。而尾部若存在比它更大的元素,它就是尾部的最大值。就这么简单!现在,我们在haskell中实现它

maximum' :: (Ord a) => [a] -> a  
maximum' [] = error "maximum of empty list"  
maximum' [x] = x  
maximum' (x:xs)   
    | x > maxTail = x  
    | otherwise = maxTail  
    where maxTail = maximum' xs


如 你所见,模式匹配与递归简直就是天造地设!大多数命令式语言中都没有模式匹配,于是你就得造一堆if-else来测试边界条件。而在这里,我们仅需要使用 模式将其表示出来。第一个模式说,如果该List为空,崩溃!就该这样,一个空List的最大值能是啥?我不知道。第二个模式也表示一个边缘条件,它说, 如果这个List仅包含单个元素,就返回该元素的值。

现在是第三个模式,执行动作的地方。 通过模式匹配,可以取得一个List的头部和尾部。这在使用递归处理List时是十分常见的。出于习惯,我们用个where语句来表示maxTail作为 该List中尾部的最大值,然后检查头部是否大于尾部的最大值。若是,返回头部;若非,返回尾部的最大值。

我们取个List [2,5,1]做例子来看看它的工作原理。当调用maximum'处理它时,前两个模式不会被匹配,而第三个模式匹配了它并将其分为2与[5,1]。 where子句再取[5,1]的最大值。于是再次与第三个模式匹配,并将[5,1]分割为5和[1]。继续,where子句取[1]的最大值,这时终于到 了边缘条件!返回1。进一步,将5与[1]的最大值做比较,易得5,现在我们就得到了[5,1]的最大值。再进一步,将2与[5,1]的最大值相比较,可 得5更大,最终得5。

使用max函数会使代码更加清晰。如果你还记得,max函数取两个值做参数并返回其中较大的值。如下便是用max函数重写的maximun'

maximum' :: (Ord a) => [a] -> a  
maximum' [] = error "maximum of empty list"  
maximum' [x] = x  
maximum' (x:xs) = max x (maximum' xs) 

太漂亮啦!一个List的最大值就是它的首个元素与它尾部中最大值相比较所得的结果,简明扼要。

你可能感兴趣的:(haskell,max)