Function
defineName param = f(param)
模式匹配(pattern matching)為不同的模式分別定義函數(shù)體州邢,注意匹配所有情況的模式應(yīng)寫到最后伐蒂,類似switch/case,但匹配的是結(jié)構(gòu)拆吆,關(guān)系具體內(nèi)容的是哨位(guard)聋迎。
某種意義上函數(shù)名后的參數(shù)判斷本身就是“模式匹配”,注意類型注解和模式匹配中的括號意味著元組和表達(dá)式
兩種情況枣耀,由于元組內(nèi)部被逗號分隔霉晕,容易分辨
defineName1 :: type1->type2
defineName1 a = f()
defineName1 x = f(x)
guard通過檢查參數(shù)的性質(zhì)是否為真(布爾判斷),契合模式匹配的多條件分支捞奕。模式與guard相似的地方是對內(nèi)容的判斷(模式的結(jié)構(gòu)包含內(nèi)容)牺堰,稍微不同的是guard能對參數(shù)組合后的內(nèi)容進(jìn)行判斷。
元組的模式匹配指將每個成員分別寫出來
列表中[]匹配空列表缝彬,可以用: 與 []匹配非空列表萌焰,x:xs將列表的頭部綁定為x,余下部分為xs谷浅。
x:y:[]相當(dāng)于[x,y]匹配長度固定的列表扒俯。
不能在列表的模式匹配中使用++,
as模式(as-pattern),允許按模式將一個值分隔成多個項一疯,同時仍保留對其整體的引用撼玄。
如all@(x:y)
Prelude> firstletter all@(x:y) = "The first letter of "++all++" is "++[x]
Prelude> firstletter ['a','c','d']
"The first letter of acd is a"
case
模式匹配是case表達(dá)式的語法糖,函數(shù)參數(shù)的模式匹配只能在定義函數(shù)時使用墩邀,而case表達(dá)式可用在任何地方掌猛,始終沒有匹配的模式,將會產(chǎn)生運行時錯誤眉睹,注意用空格縮進(jìn)荔茬。注意typeclass與pattern的差別。
case expression of pattern -> result
pattern -> result
pattern -> result
...
where
函數(shù)where中定義的名字只對本函數(shù)可見竹海,不必?fù)?dān)心它會污染其它函數(shù)的命名空間慕蔚。如果要對不同的函數(shù)重復(fù)使用到同一名字,應(yīng)把它置于全局定義中斋配】嘴可以在where綁定中使用模式匹配和定義函數(shù)灌闺,但where中定義的名字不能在函數(shù)的其它模式訪問?,最后一個模式可見坏瞄,guard也可見桂对。
let
let表達(dá)式的格式為let <bindings> in <expressions>。綁定的名字僅對in部分可見鸠匀,本身是表達(dá)式一定有返回值蕉斜。let把綁定語句放前面,后跟表達(dá)式狮崩,與where相反蛛勉。(指where與其函數(shù)的整體)鹿寻。直接在GHCi中定義let可省略in睦柴,這樣名字的定義在整個會話中可見,由于沒有in也不會出現(xiàn)返回值毡熏。
Prelude> let havefun x y = [x..y]
Prelude> havefun 1 5
[1,2,3,4,5]
Prelude> let hadfun x y = [x..y] in hadfun 3 7
[3,4,5,6,7]
Prelude> hadfun
<interactive>:61:1: error:
? Variable not in scope: hadfun
? Perhaps you meant ‘havefun’ (line 58)
list (列表是單類型的)
- 字符串是一組字符組成的列表坦敌,"hello"是['h','e','l','l','o']的語法糖
- [1,2,3]是1:2:3:[]的語法糖
- 嵌套列表的元素同樣不能混合放置類型
a. 拼接字符串 list ++ list(會遍歷第一個列表)
b. 添加字符串 element : list
c. 訪問元素 list(string) !! index
d. 比較元素 <、 >痢法、 >=狱窘、<=、==财搁、 /=
e. 邏輯符號 &&蘸炸、||、not
f. 列表頭尾操作 head尖奔、tail搭儒、last、init (不要用到空列表[]上)
g. 列表屬性 length返回長度提茁,null檢查是否為空淹禾,reverse反轉(zhuǎn)列表,maximum取最大元素茴扁,minimum取最小元素铃岔,sum與product返回和與積
h. 截取操作,take number list 取出列表的前number個峭火,返回列表毁习;drop number list 返回刪除前number個的列表。element elem list判斷元素是否包含于列表
i. 區(qū)間卖丸,[a,n*a..b], [a..b],[a,n*a..]纺且。cycle函數(shù)接受一個列表作為參數(shù)并返回一個無限列表;repeat函數(shù)接受一個值作為參數(shù)坯苹,返回一個僅包含該值的無限列表隆檀。replicate接受列表長度和復(fù)制的元素,takeWhile取一個謂詞和列表作為參數(shù),在元素符合謂詞時返回元素恐仑,一旦不符合條件就停止泉坐,返回結(jié)果列表,注意與filter的區(qū)別裳仆。
j. odd 判斷一個數(shù)是否為奇數(shù)腕让,even判斷一個數(shù)是否為偶數(shù)
Prelude> take 7 (repeat 6)
[6,6,6,6,6,6,6]
Prelude> take 17 (cycle "yukipedia")
"yukipediayukipedi"
Prelude> [0.1,0.2..1]
[0.1,0.2,0.30000000000000004,0.4000000000000001,0.5000000000000001,0.6000000000000001,0.7000000000000001,0.8,0.9,1.0]
Prelude> [1,(-2)..(-20)]
[1,-2,-5,-8,-11,-14,-17,-20]
list comprehension
[f(x,y)|x<-set,y<-set,predicate(x,y),let <bindins> in <expressions>]
列表推導(dǎo)式自然是產(chǎn)生列表的咯
分別演示了自定義length函數(shù)(每次元素滿足謂詞,執(zhí)行f)歧斟、取出大寫字符(處理字符串)纯丸、不拆開嵌套列表而去除奇數(shù)(始終返回列表)
Prelude> [x * y | x<-[1,2,3], y<-[10,12,14],x*y>20]
[24,28,30,36,42]
Prelude> length' xs = sum [1|_<-xs]
Prelude> length' [1..20]
20
Prelude> removeNonUppercase st = [c|c<-st,c `elem`['A'..'Z']]
Prelude> removeNonUppercase "yuKiPEdiA"
"KPEA"
Prelude> let nestList = [[2,3,4,5],[6,7,8,9],[10,11,12,13,14]]
Prelude> [[x|x<-nL,even x]|nL<-nestList]
[[2,4],[6,8],[10,12,14]]
tuple
元組是異構(gòu)的,并且長度固定静袖,由括號括起觉鼻,由逗號隔開 。長度為2的元組(序?qū)Χ映龋琾air)與長度為3的元組(三元組坠陈,triple)被視為不同的類型。進(jìn)一步捐康,兩個元組要類型相同仇矾,需要每一項的類型都彼此對應(yīng)。毫無疑問解总,每個元組都可能是個獨特的類型贮匕。正因為如此,允許單元素的list花枫,卻不允許單元素的tuple刻盐。單純用括號包含單元素,最終也只是作為表達(dá)式得到單元素乌昔∠毒危空元組類型為()。
- fst取一個序?qū)?/em>作為參數(shù)磕道,返回其首項供屉。snd返回其尾項。
- zip list list 返回交叉配對的一組序?qū)?/em>溺蕉。
Prelude> zip [1..] ["yukino","yui","hiki"]
[(1,"yukino"),(2,"yui"),(3,"hiki")]
接下來演示一個實際問題伶丐,求三條邊為1..10的整數(shù),和為24的直角三角形疯特。函數(shù)式一般思路:先去一個初始的集合并將其變形哗魂,隨后持續(xù)地利用過濾條件縮小計算范圍。
Prelude> let rightTriangles' = [(a,b,c)|c<-[1..10],a<-[1..c],b<-[a..c-1],a^2+b^2==c^2,a+b+c==24]
Prelude> rightTriangles'
[(6,8,10)]
基本數(shù)據(jù)類型
a.Int為有界整數(shù)漓雅,Integer無界录别,效率低于Int
b.Float 單精點浮點數(shù)朽色,Double雙精點
c.Bool布爾值
d.Char 表示一個Unicode字符,一個字符由單引號括起组题,一組字符的列表即字符串
e.凡是類型首字母大寫葫男,()除外
f.Odering類型有GT,LT崔列,EQ三種值梢褐,分別表示大于,小于赵讯,等于
g.String是[Char]的別名
類型推斷
:t 命令接受任何合法的表達(dá)式盈咳,返回其類型。:: 讀作“它的類型為”边翼。 后面可能會有type constraint鱼响,一定會有參數(shù)類型,最后一個參數(shù)代表返回值讯私。
對函數(shù)而言可以“靜態(tài)類型檢查”諸如factorial1 :: Integer -> Integer factorial1 n = sum[1..n]
限制輸入?yún)?shù)热押。
當(dāng)對判斷性質(zhì)的運算符西傀,如==斤寇,+,-拥褂,使用:t時娘锁,需要用(),如:t (==)。其實當(dāng)中綴函數(shù)要作為參數(shù)或者前綴函數(shù)調(diào)用時饺鹃,都需要用括號括起莫秆。可以中綴形式定義函數(shù)悔详,通過反引號镊屎。
Prelude> :t "yukipedia"
"yukipedia" :: [Char]
Prelude> factorial n = product [1..n]
Prelude> :t factorial
factorial :: (Num a, Enum a) => a -> a
Prelude> :t head
head :: [a] -> a
類型注解(type annotation)
編譯器可以辨認(rèn)出大部分表達(dá)式的類型,但有時需要提示具體的類型茄螃。類型注解跟在表達(dá)式后面缝驳,通過 :: 分隔,顯式表達(dá)類型归苍。
Prelude> read "True"
*** Exception: Prelude.read: no parse
Prelude> read "True"||False
True
Prelude> [read "True",False]
[True,False]
Prelude> (read "True",False)
(*** Exception: Prelude.read: no parse
Prelude> read "True"::Bool
True
Prelude> read "True"::Int
*** Exception: Prelude.read: no parse
類型變量(type variable)
形如head函數(shù)的類型判斷中的a用狱,a可以是任何類型,使用類型變量的函數(shù)被稱為多態(tài)函數(shù)(polymorphic function)拼弃。命名上夏伊,類型變量可以使用多個字符,不過一般約定為單字符吻氧,如a,b,c,d...溺忧。另外不同字符的類型變量并非意味兩者表示的類型一定不同咏连。
=>左側(cè)叫做類型約束(type constraint),暫時認(rèn)為類型變量始終泛指,而類型約束提供了范圍
多態(tài)常量(polymorphic constant)指類型約束后 (typeclass a)=> a 這個函數(shù)輸入輸出沒有變化鲁森?所有的數(shù)都是多態(tài)常量
Prelude> :t 7.0
7.0 :: Fractional p => p
Prelude> :t 7
7 :: Num p => p
類型類(typeclass)
typeclass是一組函數(shù)的集合捻勉,type constraint => type variable->type variable->..->type variable,所有變量都有類型刀森,如果該類型是某typeclass的instance踱启,那么它必須實現(xiàn)該類型所描述的行為。typeclass是定義行為的接口研底。即instance(變量所屬的類型)具備執(zhí)行“描述的行為”的能力埠偿,typeclass為定義行為的接口。
1.Eq類型類用于判可斷相等性的類型榜晦,它的實例必須實現(xiàn)==和/=兩個函數(shù)冠蒋。
2.Ord類型類用于可比較大小的類型
3.Show類型類的實例為可以表示為字符串的類型
4.Read類型類與Show相反,將字符串轉(zhuǎn)化為某類型
5.Enum類型類包含()乾胶、Bool抖剿、Char、Ordering识窿、Int斩郎、Integer、Float喻频、Double等類型(實例),可作為succ函數(shù)和pred函數(shù)的參數(shù)
6.Bounded類型類的實例類型可以通過maxBound和minBound得到其上限和下限缩宜,如果元組中的項的類型都屬于Bounded類型類的實例,那么這個元組也屬于Bounded的實例甥温。
7.Num類型類的實例類型為Int锻煌、Integer、Float姻蚓、Double等宋梧,只有屬于Show和Eq的實例類型,才可以成為Num類型類的實例
8.Floating類型類僅包含F(xiàn)loat和Double兩種浮點類型
9.Integeral僅與整數(shù)有關(guān)狰挡,實例類型為Int和Integer
a.所有標(biāo)準(zhǔn)類型都是Eq類的實例(除與輸入輸出相關(guān)的類型和函數(shù)之外)
b.除函數(shù)以外捂龄,以上所有類型都是Ord,Read圆兵,Show的實例
c.typeclass含有多個類型作為實例跺讯,一個類型可以作為多個typeclass的實例。一個類型必須在成為某typeclass的實例后殉农,才能成為另一個typeclas的實例
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
Prelude> fromIntegral (3)+3.2
6.2
Prelude> 3 + 3.2
6.2
Prelude> (3 :: Int)+3.2
<interactive>:39:12: error:
? No instance for (Fractional Int) arising from the literal ‘3.2’
? In the second argument of ‘(+)’, namely ‘3.2’
In the expression: (3 :: Int) + 3.2
In an equation for ‘it’: it = (3 :: Int) + 3.2
Prelude> (3 :: Float)+3.2
6.2