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

歡迎關注我的github
https://github.com/luckyCatMiao

發佈了108 篇原創文章 · 獲贊 64 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章