Function
defineName param = f(param)
模式匹配(pattern matching)為不同的模式分別定義函數(shù)體,注意匹配所有情況的模式應(yīng)寫到最后,類似switch/case,但匹配的是結(jié)構(gòu),關(guān)系具體內(nèi)容的是哨位(guard)。
某種意義上函數(shù)名后的參數(shù)判斷本身就是“模式匹配”,注意類型注解和模式匹配中的括號(hào)意味著元組和表達(dá)式
兩種情況,由于元組內(nèi)部被逗號(hào)分隔,容易分辨
defineName1 :: type1->type2
defineName1 a = f()
defineName1 x = f(x)
guard通過(guò)檢查參數(shù)的性質(zhì)是否為真(布爾判斷),契合模式匹配的多條件分支。模式與guard相似的地方是對(duì)內(nèi)容的判斷(模式的結(jié)構(gòu)包含內(nèi)容),稍微不同的是guard能對(duì)參數(shù)組合后的內(nèi)容進(jìn)行判斷。
元組的模式匹配指將每個(gè)成員分別寫出來(lái)
列表中[]匹配空列表,可以用: 與 []匹配非空列表,x:xs將列表的頭部綁定為x,余下部分為xs。
x:y:[]相當(dāng)于[x,y]匹配長(zhǎng)度固定的列表。
不能在列表的模式匹配中使用++,
as模式(as-pattern),允許按模式將一個(gè)值分隔成多個(gè)項(xiàng),同時(shí)仍保留對(duì)其整體的引用。
如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á)式的語(yǔ)法糖,函數(shù)參數(shù)的模式匹配只能在定義函數(shù)時(shí)使用,而case表達(dá)式可用在任何地方,始終沒有匹配的模式,將會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤,注意用空格縮進(jìn)。注意typeclass與pattern的差別。
case expression of pattern -> result
pattern -> result
pattern -> result
...
where
函數(shù)where中定義的名字只對(duì)本函數(shù)可見,不必?fù)?dān)心它會(huì)污染其它函數(shù)的命名空間。如果要對(duì)不同的函數(shù)重復(fù)使用到同一名字,應(yīng)把它置于全局定義中??梢栽趙here綁定中使用模式匹配和定義函數(shù),但where中定義的名字不能在函數(shù)的其它模式訪問(wèn)?,最后一個(gè)模式可見,guard也可見。
let
let表達(dá)式的格式為let <bindings> in <expressions>。綁定的名字僅對(duì)in部分可見,本身是表達(dá)式一定有返回值。let把綁定語(yǔ)句放前面,后跟表達(dá)式,與where相反。(指where與其函數(shù)的整體)。直接在GHCi中定義let可省略in,這樣名字的定義在整個(gè)會(huì)話中可見,由于沒有in也不會(huì)出現(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']的語(yǔ)法糖
- [1,2,3]是1:2:3:[]的語(yǔ)法糖
- 嵌套列表的元素同樣不能混合放置類型
a. 拼接字符串 list ++ list(會(huì)遍歷第一個(gè)列表)
b. 添加字符串 element : list
c. 訪問(wèn)元素 list(string) !! index
d. 比較元素 <、 >、 >=、<=、==、 /=
e. 邏輯符號(hào) &&、||、not
f. 列表頭尾操作 head、tail、last、init (不要用到空列表[]上)
g. 列表屬性 length返回長(zhǎng)度,null檢查是否為空,reverse反轉(zhuǎn)列表,maximum取最大元素,minimum取最小元素,sum與product返回和與積
h. 截取操作,take number list 取出列表的前number個(gè),返回列表;drop number list 返回刪除前number個(gè)的列表。element elem list判斷元素是否包含于列表
i. 區(qū)間,[a,n*a..b], [a..b],[a,n*a..]。cycle函數(shù)接受一個(gè)列表作為參數(shù)并返回一個(gè)無(wú)限列表;repeat函數(shù)接受一個(gè)值作為參數(shù),返回一個(gè)僅包含該值的無(wú)限列表。replicate接受列表長(zhǎng)度和復(fù)制的元素,takeWhile取一個(gè)謂詞和列表作為參數(shù),在元素符合謂詞時(shí)返回元素,一旦不符合條件就停止,返回結(jié)果列表,注意與filter的區(qū)別。
j. odd 判斷一個(gè)數(shù)是否為奇數(shù),even判斷一個(gè)數(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)的,并且長(zhǎng)度固定,由括號(hào)括起,由逗號(hào)隔開 。長(zhǎng)度為2的元組(序?qū)?,pair)與長(zhǎng)度為3的元組(三元組,triple)被視為不同的類型。進(jìn)一步,兩個(gè)元組要類型相同,需要每一項(xiàng)的類型都彼此對(duì)應(yīng)。毫無(wú)疑問(wèn),每個(gè)元組都可能是個(gè)獨(dú)特的類型。正因?yàn)槿绱?,允許單元素的list,卻不允許單元素的tuple。單純用括號(hào)包含單元素,最終也只是作為表達(dá)式得到單元素。空元組類型為()。
- fst取一個(gè)序?qū)?/em>作為參數(shù),返回其首項(xiàng)。snd返回其尾項(xiàng)。
- zip list list 返回交叉配對(duì)的一組序?qū)?/em>。
Prelude> zip [1..] ["yukino","yui","hiki"]
[(1,"yukino"),(2,"yui"),(3,"hiki")]
接下來(lái)演示一個(gè)實(shí)際問(wèn)題,求三條邊為1..10的整數(shù),和為24的直角三角形。函數(shù)式一般思路:先去一個(gè)初始的集合并將其變形,隨后持續(xù)地利用過(guò)濾條件縮小計(jì)算范圍。
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無(wú)界,效率低于Int
b.Float 單精點(diǎn)浮點(diǎn)數(shù),Double雙精點(diǎn)
c.Bool布爾值
d.Char 表示一個(gè)Unicode字符,一個(gè)字符由單引號(hào)括起,一組字符的列表即字符串
e.凡是類型首字母大寫,()除外
f.Odering類型有GT,LT,EQ三種值,分別表示大于,小于,等于
g.String是[Char]的別名
類型推斷
:t 命令接受任何合法的表達(dá)式,返回其類型。:: 讀作“它的類型為”。 后面可能會(huì)有type constraint,一定會(huì)有參數(shù)類型,最后一個(gè)參數(shù)代表返回值。
對(duì)函數(shù)而言可以“靜態(tài)類型檢查”諸如factorial1 :: Integer -> Integer factorial1 n = sum[1..n]限制輸入?yún)?shù)。
當(dāng)對(duì)判斷性質(zhì)的運(yùn)算符,如==,+,-,使用:t時(shí),需要用(),如:t (==)。其實(shí)當(dāng)中綴函數(shù)要作為參數(shù)或者前綴函數(shù)調(diào)用時(shí),都需要用括號(hào)括起??梢灾芯Y形式定義函數(shù),通過(guò)反引號(hào)。
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á)式的類型,但有時(shí)需要提示具體的類型。類型注解跟在表達(dá)式后面,通過(guò) :: 分隔,顯式表達(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)。命名上,類型變量可以使用多個(gè)字符,不過(guò)一般約定為單字符,如a,b,c,d...。另外不同字符的類型變量并非意味兩者表示的類型一定不同。
=>左側(cè)叫做類型約束(type constraint),暫時(shí)認(rèn)為類型變量始終泛指,而類型約束提供了范圍
多態(tài)常量(polymorphic constant)指類型約束后 (typeclass a)=> a 這個(gè)函數(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,那么它必須實(shí)現(xiàn)該類型所描述的行為。typeclass是定義行為的接口。即instance(變量所屬的類型)具備執(zhí)行“描述的行為”的能力,typeclass為定義行為的接口。
1.Eq類型類用于判可斷相等性的類型,它的實(shí)例必須實(shí)現(xiàn)==和/=兩個(gè)函數(shù)。
2.Ord類型類用于可比較大小的類型
3.Show類型類的實(shí)例為可以表示為字符串的類型
4.Read類型類與Show相反,將字符串轉(zhuǎn)化為某類型
5.Enum類型類包含()、Bool、Char、Ordering、Int、Integer、Float、Double等類型(實(shí)例),可作為succ函數(shù)和pred函數(shù)的參數(shù)
6.Bounded類型類的實(shí)例類型可以通過(guò)maxBound和minBound得到其上限和下限,如果元組中的項(xiàng)的類型都屬于Bounded類型類的實(shí)例,那么這個(gè)元組也屬于Bounded的實(shí)例。
7.Num類型類的實(shí)例類型為Int、Integer、Float、Double等,只有屬于Show和Eq的實(shí)例類型,才可以成為Num類型類的實(shí)例
8.Floating類型類僅包含F(xiàn)loat和Double兩種浮點(diǎn)類型
9.Integeral僅與整數(shù)有關(guān),實(shí)例類型為Int和Integer
a.所有標(biāo)準(zhǔn)類型都是Eq類的實(shí)例(除與輸入輸出相關(guān)的類型和函數(shù)之外)
b.除函數(shù)以外,以上所有類型都是Ord,Read,Show的實(shí)例
c.typeclass含有多個(gè)類型作為實(shí)例,一個(gè)類型可以作為多個(gè)typeclass的實(shí)例。一個(gè)類型必須在成為某typeclass的實(shí)例后,才能成為另一個(gè)typeclas的實(shí)例
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