Haskell 筆記 (五) 遞歸

haskell 遞歸

遞歸就是將問題展開爲同樣的子問題,並不斷的對子問題展開,直到抵達問題的基準條件爲止。

遞歸2個要點:

  1. 問題如何展開爲子問題
  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]

遞歸總結

遞歸函數有固定的模式

  1. 先定義基準, 也就是特殊輸入的簡單非遞歸解。
  2. 分解問題,遞歸調用自身,基於子問題的結果,組合爲最終解。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章