haskell 遞歸
遞歸
就是將問題展開爲同樣的子問題,並不斷的對子問題展開,直到抵達問題的基準條件爲止。
遞歸2個要點:
- 問題如何展開爲子問題
- 定義基準條件
在程序上,問題的展開表現就是函數調用函數自己。基準條件就是結束展開的條件。
求列表最大值
maxNumOfList :: (Ord a)=> [a] -> a
maxNumOfList [] = error "empty list"
maxNumOfList [x] = x
maxNumOfList (x:xs) = max x (maxNumOfList xs)
遞歸練習
使用遞歸實現幾個haskell已有的函數
replicate
生成一個列表有n個元素的列表,列表個數爲第一參數,列表元素爲第二參數。
Prelude> replicate 3 5
[5,5,5]
實現
replicate' :: Int -> a -> [a]
replicate' n x
| n <= 0 = []
| otherwise = x:replicate' (n-1) x
take
從列表中去一定數量的元素, 第一個參數爲元素個數,第二個參數爲列表
Prelude> take 3 [9,8,7,6,5,4,3]
[9,8,7]
實現
take' :: (Num i, Ord i) => i -> [a] -> [a]
take' n _
| n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n-1) xs
reverse
反轉列表
Prelude> reverse [9,8,7,6,5,4,3]
[3,4,5,6,7,8,9]
實現
reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
注意:在列表頭插入用":", 在尾部拼接用"++", 列表大的情況下,使用"++"效率不高。
repreat
返回一個包含元素的無限列表,第一個參數爲元素。
Prelude> repeat 3
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,Interrupted.
實現
repeat' :: a -> [a]
repeat' x = x: repeat' x
zip
將2個列表作爲輸入,返回捆綁了2個列表元素的列表。會截斷長列表,以短列表爲準。
Prelude> zip [1, 2, 3] [4, 5, 6]
[(1,4),(2,5),(3,6)]
實現
*Main> zip' [1, 2, 3] [4, 5, 6]
[(1,4),(2,5),(3,6)]
elem
判斷元素是否在列表中
Prelude> elem 6 [6, 7, 8, 9]
True
Prelude> elem 5 [6, 7, 8, 9]
False
實現
elem' :: (Eq a) => a -> [a] -> Bool
elem' _ [] = False
elem' a (x:xs)
| a == x = True
| otherwise = elem' a xs
快速排序的實現
quickSort :: (Ord a) => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = --以x爲基準
let smallerOrEqual = [a | a <- xs, a <=x] --小於等於x的序列
larger = [a | a <- xs, a > x] --大於x的序列
in quickSort smallerOrEqual ++ [x] ++ quickSort larger --組合拼接列表
執行
*Main> quickSort [1, 3, 6, 8, 9, 5, 4, 2]
[1,2,3,4,5,6,8,9]
遞歸總結
遞歸函數有固定的模式
- 先定義基準, 也就是特殊輸入的簡單非遞歸解。
- 分解問題,遞歸調用自身,基於子問題的結果,組合爲最終解。