haskell學習筆記(4)-函數入門

模式匹配 (Pattern matching)

haskell可以定義同名函數,然後會根據聲明順序搜索與傳入參數最接近的函數簽名,然後調用那個函數,可以看成是強化版的函數重載。模式匹配的參數可以是字面量

--調用名爲lucky的函數時,匹配情況爲
--匹配傳入參數是7的情況
lucky 7 = "LUCKY NUMBER SEVEN!" 
--匹配任意的單個傳入參數
lucky x = "Sorry, you're out of luck, pal!"  

--如果聲明順序翻轉,則lucky x會先於捕獲所有的參數,和其他語言中(c/c++ java)搜索最接近的函數簽名不同。



再看一個例子

sayMe 1 = "One!" 
sayMe 2 = "Two!" 
sayMe 3 = "Three!" 
sayMe 4 = "Four!" 
sayMe 5 = "Five!" 
sayMe x = "Not between 1 and 5"



根據此特性實現的遞歸階乘

factorial 0 = 1 
factorial n = n * factorial (n - 1)



除了能夠聲明字面量外,函數的參數還可以是列表,元組的一部分

--捕獲了一個列表的三個值,然後直接將他們相加(要實現同樣的行爲在java中需要在方法內取出三個值並聲明局部變量)
--_表示捕獲剩餘的變量並拋棄
add (x:y:z:_) = x +y+z



實現一個遞歸的求數組長度

--遞歸觸底返回
length' [] = 0 
--_匹配開頭,xs是一個關鍵字,匹配所有的剩餘元素,和_不同的是他可以引用,而_直接拋棄捕獲到的元素,有點像正則的(?:)
--遞歸將length看成1+剩餘部分的長度
length' (_:xs) = 1 + length' xs 



說白了,這個東西就是將一些用到的局部變量用語法糖聲明在參數裏了,可以少寫不少代碼,不過問題就是有時候比較複雜的函數聲明有點難看懂。


Guards

模式匹配只能匹配精確值例如”a”,”b”,”c”,以及列表的部分例如(x:y:_),Guards則是匹配參數的域,有點像常規的switch語句。

--當其他語言的switch來看一下就理解了
bmiTell bmi
| bmi <= 18.5 = "You're underweight, you emo, you!"
| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
| bmi <= 30.0 = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!" 
bmiTell weight height
| weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!"
| weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
| weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!"
--otherwise就相當於其他語言switch裏的default
| otherwise = "You're a whale, congratulations!" 
--聲明成中綴函數的形式
a `myCompare` b 
   | a > b   = GT 
   | a == b   = EQ 
   | otherwise = LT 



haskell的Guards將一個函數分成了兩部分,一部分是匹配結果值,還有一部分是where部分用於聲明局部變量。想想我們往常在命令式語言裏寫的函數,也是先聲明局部變量,然後處理,最後判斷返回值。

唯一的不同就是haskell是將局部變量的聲明後置,跟在where的後面

bmiTell weight height
| bmi <= 18.5 = "You're underweight, you emo, you!"
| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
| bmi <= 30.0 = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!"
--bmi就聲明瞭一個局部變量
where bmi = weight / height ^ 2
bmiTell weight height
| bmi <= skinny = "You're underweight, you emo, you!"
| bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"
| bmi <= fat = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!"
--聲明多個局部變量
where bmi = weight / height ^ 2
skinny = 18.5
normal = 25.0
fat = 30.0

where 綁定也可以使用模式匹配,上面的where部分還可以寫成

where bmi = weight / height ^ 2 
    (skinny, normal, fat) = (18.5, 25.0, 30.0)

在看一個函數的時候,應該先看where部分,再看匹配部分

where部分還可以定義函數

--在列表內部調用Bmi函數
calcBmis xs = [bmi w h | (w, h) <- xs]
--定義bmi函數,此函數只在外部函數xs內可見
   where bmi weight height = weight / height ^ 2 
calc xs=[bmi w h|(w,h)<-xs]
  where
    bmi w h=w/h^2



let 綁定與 where 綁定很相似,不同的是let是前置聲明

cylinder r h =
   let sideArea = 2 * pi * r * h 
     topArea = pi * r ^2 
   in  sideArea + 2 * topArea 

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

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