haskell学习笔记(4)-函数入门

来源:互联网 发布:淘宝图片空间删不掉 编辑:程序博客网 时间:2024/06/14 10:32

模式匹配 (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 ^ 2skinny = 18.5normal = 25.0fat = 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