程序员函数式语言Haskell

Haskell入门(四):递归(recursion)

2019-01-25  本文已影响50人  _小轩窗_

参考教材:Learn You a Haskell for Great Good (http://learnyouahaskell.com/)

操作环境:Ubuntu下Linux64位虚拟机

python入门编程, 之后用c++学习数据结构,Haskell萌新。

由于对Haskell中一些词语的中文翻译并不了解,接下来的内容中重点名词将有英文和我理解的中文。


Chapter4主要内容

     递归这一章并没有特别强调函数式编程与面向对象编程的区别。事实上,递归更多地是一种思想。

    递归基本原理

        递归的主要想法是把一个大问题拆解为同类型的小问题。由于程序应该是有限的,我们要求它能在某种情景下结束运行。这种情景应当是确定的,已知的,不需要再拆解的。在编程中它被称为基础情景(base case)。

        它与数学归纳法类似。我们需要先确定最基础的情况的结果可解,再确认可以由相对小的情景相对大的情景。在函数式编程里,可以理解为“将大定义用小定义解决”。

        (题外:在这里推荐《算法引论》,虽然没有《算法导论》那么大名鼎鼎,但是这本书中对数学归纳法的理解还是很有启发性的)

        斐波那契数列是典型的用递归定义的。我们来看看它的实现。

斐波那契数列

        上面这一算法的时间效率并不好,不过我们在这里只是作为递归的例子。

    使用递归实现函数

        在了解了递归的基本原理后,我们试着用递归实现一些基础功能。

        求同类型列表的最大值(maximum)

                如果列表长度为0, 抛出错误。如果列表只有一个元素,该元素即为最大值。否则,列表的最大值是列表head与tail部分最大值的较大值。具体实现如图。  

求同类型列表的最大值

    返回指定数目的某个元素重复构成的列表(take)

            如果指定的数目不是正整数,则返回空列表。否则,返回的是重复次数减一情况下的列表,在开头加入该元素。

            

求同类型列表的最大值

            中间报错的部分是由于在使用-时,它不能确定是负数还是减号。加入括号后问题得到解决。

    取前几个元素

        如果剩余列表为空,或者剩余要取的不是正整数, 则返回空列表。否则,返回的是从tail部分取个数减一后的元素,并在开头剩余列表的head。(自己看着觉得很绕,可能看代码会好一些?)

取前几个元素

    判断某个元素是否在列表中出现   (elem) 

            如果列表为空,返回False.如果元素与列表的head相同,返回True。否则,判断元素是否在列表的tail部分出现。

判断某个元素是否在列表中出现

    列表元组对应打包(zip)

            如果某个列表为空,则返回空。否则,将两个列表的tail部分元组对应打包后,在开头加入由两个head组成的tuple。

列表元组对应打包

            如果两个列表长度不等,则某一个先达到[], 且递归部分返回[], 因而返回列表长度以两个列表中短的为准。

    快速排序(quick sort)

            递归解决快排的想法是:如果列表为空列表或者只有一个元素,那么它一定是排序好了的。否则,我们先确定一个基准(方便起见,我们取首个元素为基准),将比它大的放在它右边,比它小的放在它左边。分别排序左右两边,当两边排序完毕时,整个列表就排序完毕了。

快速排序

            一个元素的情况也可以拆解为空列表的情况,因而第四行可以省略。

            非递归解决快速排序可以参考百度百科中的代码。

上一篇下一篇

猜你喜欢

热点阅读