1. 程式人生 > >haskell學習筆記(5)-函式與遞迴

haskell學習筆記(5)-函式與遞迴

任意迴圈結構都可以轉化為遞迴,這就是haskell沒有for while也可以實現任何應用的原因。

有些問題可以很容易的看出遞迴形式(如歸併排序,快速排序),不過有的問題卻不太容易(例如查詢一組數中的最大值,統計陣列的長度)。訓練將任意問題都看成遞迴形式的能力,可以幫助我們更好的寫出haskell程式碼,甚至是脫離了haskell之後,也可以使我們解決問題時多了一件工具。更好的理解一些比較複雜的演算法(非常多的演算法都是遞迴形式)。

以遞迴的觀點看問題,就要將一個問題化解成一系列相似的小問題,同時要考慮到觸底情況,遞迴的觸底就是在某個限制條件觸發時,遞迴函式不繼續呼叫而直接返回,否則遞迴就會一直執行下去,直到爆棧為止。

haskell因為有模式匹配以及guards的存在,遞迴寫法和一般語言不太一樣,一開始會比較難理解語法。

求list的最大值

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

--等價的ruby常規寫法
def max(arr)
  min=arr[0]
  arr.each do |item|
    if item>min
      min=item
end end min end --等價的ruby遞迴寫法 def max2(arr) #求arr[0~arr.length]的最大值,然後和arr[arr.length-1]比較 _max2(arr,arr.length) end def _max2(arr, length) if length == 1 return arr[0] end max=_max2(arr,length-1) if max>arr[length-1] return max else return arr[length-1] end end
--可以看出,haskell即使是對比以簡潔著稱的ruby,他的遞迴程式碼量也非常少,所以他的語法結構是十分適合寫遞迴函式的。

replicate 函式, 它取一個 Int 值和一個元素做引數, 返回一個包
含多個重複元素的 List, 如 replicate 3 5 返回 [5,5,5]

replicate' n x
| n <= 0 = []
| otherwise = x:replicate' (n-1) x

take 函式, 它可以從一個 List 取出一定數量的元素. 如
take 3 [5,4,3,2,1], 得 [5,4,3],注意他有兩個觸底情況

take' n _
| n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n-1) xs

reverse 函式簡單地反轉一個 List

reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]

查詢

contain' a [] = False
contain' a (x:xs)
| a == x = True
| otherwise = contain' a xs 

快速排序(因為列表描述法的存在程式碼短的不可思議)
(不過這個需要額外的空間貌似,常規的快排是直接在單個數組的swap的,他這個是先分兩個再合併)

quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSorted