Haskell常用數(shù)據(jù)形式與函數(shù)

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 (列表是單類型的)

  1. 字符串是一組字符組成的列表,"hello"是['h','e','l','l','o']的語(yǔ)法糖
  2. [1,2,3]是1:2:3:[]的語(yǔ)法糖
  3. 嵌套列表的元素同樣不能混合放置類型
    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á)式得到單元素。空元組類型為()。

  1. fst取一個(gè)序?qū)?/em>作為參數(shù),返回其首項(xiàng)。snd返回其尾項(xiàng)。
  2. 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,246評(píng)論 0 38
  • 《六項(xiàng)精進(jìn)》 大綱,背誦1遍,共368遍 《 大學(xué)》誦讀1遍,共228遍 其他經(jīng)典 活法 日行一善,完成 日省一事...
    a92bbf37be2b閱讀 187評(píng)論 0 0
  • 《大三小三》 隔壁家的孩子大三畢業(yè)了又去當(dāng)了小三 《怦然心動(dòng)》 要不是你說(shuō)“我們”我不會(huì)怦然心動(dòng) 《重量級(jí)》 記住...
    何鯨洛閱讀 285評(píng)論 0 1
  • 我是從十萬(wàn)傷心的大山里走來(lái)的人 我扛著黑色的鋤頭 帶著辛勤的思念 我一點(diǎn)點(diǎn)在愛你的路上耕耘 我在耕耘的時(shí)候背后被人...
    梵夜閱讀 210評(píng)論 0 4
  • 瑣事記8.6 前幾天,母親熱得難受,晚上睡不著,她對(duì)我說(shuō),想要裝個(gè)空調(diào)。我說(shuō),好的,我來(lái)支付空調(diào)的的費(fèi)用。 第二天...
    小棕櫚閱讀 352評(píng)論 0 1

友情鏈接更多精彩內(nèi)容