1. 類型
類型用來(lái)區(qū)分內(nèi)存中對(duì)程序員來(lái)說(shuō)不同種類的數(shù)據(jù)塊
而內(nèi)存中存儲(chǔ)的是表達(dá)式的值
所以厂庇,區(qū)分內(nèi)存塊的類型觉啊,就是區(qū)分表達(dá)式的類型
靜態(tài)類型嘉抒,指的是在編譯時(shí)就能確定表達(dá)式的類型
動(dòng)態(tài)類型姿鸿,指的是在運(yùn)行時(shí)才能確定表達(dá)式的類型
注:
靜態(tài)類型殖卑,也可以說(shuō)站削,通過(guò)代碼文本就能確定表達(dá)式的類型
強(qiáng)類型和弱類型是相對(duì)而言的
類型系統(tǒng)的強(qiáng)度指的是,在多大程度上能把表達(dá)式看做是合法類型的
類型強(qiáng)度的表現(xiàn)形式是孵稽,是否允許隱式類型轉(zhuǎn)換
弱類型许起,更允許隱式類型轉(zhuǎn)換
強(qiáng)類型,更不允許隱式類型轉(zhuǎn)換
2. 定義類型
Haskell中定義類型的方式有以下幾種
(1)使用type定義類型別名
type MyTuple = (Int, String)
定義MyTuple
為元組類型(Int, String)
的別名
(2)使用data定義新類型
data BookType = BookValue Int String
其中菩鲜,BookType
是類型名园细,又稱為類型構(gòu)造器,BookValue
稱為值構(gòu)造器
一個(gè)BookType
類型值接校,可以這樣定義
let bookValue = BookValue 12 "ab"
注:
因?yàn)轭愋蜆?gòu)造器和值構(gòu)造器會(huì)在不同上下文中使用猛频,所以經(jīng)常把它們寫為同一個(gè)名字
data Book = Book Int String
遇到名字Book
時(shí)要小心區(qū)分
(3)使用newtype
為已有類型定義新的標(biāo)識(shí)
newtype
定義的類型狮崩,只能有一個(gè)值構(gòu)造器,且值構(gòu)造器只能有一個(gè)字段
例如:
一個(gè)值構(gòu)造器鹿寻,值構(gòu)造器只有一個(gè)字段睦柴,可以
newtype Okay = ExactlyOne Int
類型構(gòu)造器有多個(gè)參數(shù),但是只有一個(gè)值構(gòu)造器毡熏,值構(gòu)造器只有一個(gè)字段坦敌,也可以
newtype Param a b = Param (Either a b)
字段訪問器語(yǔ)法,可以
newtype Record = Record {
getInt :: Int
}
注:
字段訪問器語(yǔ)法痢法,同時(shí)定義了字段的類型Int
狱窘,以及字段的訪問器函數(shù)getInt :: Record -> Int
例如:
通過(guò)值構(gòu)造器Record
構(gòu)造該類型的值,Record 12
通過(guò)訪問器提取字段的值疯暑,getInt (Record 12)
有一個(gè)值構(gòu)造器训柴,但是值構(gòu)造器沒有字段,不可以
newtype TooFew = TooFew
有一個(gè)值構(gòu)造器妇拯,但是值構(gòu)造器有兩個(gè)字段幻馁,不可以
newtype TooManyFields = Fields Int Int
有多個(gè)值構(gòu)造器,不可以
newtype TooManyCtors = Bad Int
| Worse Int
3. 帶參數(shù)的類型
類型構(gòu)造器也可以帶參數(shù)
data Maybe a = Nothing
| Just a
data Either a b = Left a
| Right b
其中越锈,Maybe
是類型構(gòu)造器仗嗦,Maybe Int
才是一個(gè)具體的類型
Either
是類型構(gòu)造器,Either Int String
才是一個(gè)具體的類型
注:
與函數(shù)的Currying相似甘凭,類型構(gòu)造器也可以Currying
Either
是一個(gè)類型構(gòu)造器稀拐,提供兩個(gè)類型Int
和String
,得到類型Either Int String
Either Int
也是一個(gè)類型構(gòu)造器丹弱,提供類型String
德撬,得到類型Either Int String
4. newtype
使用newtype
為已有類型定義編譯時(shí)的新標(biāo)識(shí),
這個(gè)標(biāo)識(shí)在運(yùn)行時(shí)會(huì)轉(zhuǎn)換為原有的類型躲胳,可以稱為去殼
例如:
定義新的類型
data DataInt = D Int
deriving (Eq, Ord, Show)
定義編譯時(shí)的類型外殼
newtype NewtypeInt = N Int
deriving (Eq, Ord, Show)
運(yùn)行時(shí)蜓洪,求值undefined
會(huì)發(fā)生錯(cuò)誤
ghci> undefined
*** Exception: Prelude.undefined
運(yùn)行時(shí),_
可以匹配所有坯苹,undefined
不求值
ghci> case D undefined of D _ -> 1
1
運(yùn)行時(shí)隆檀,N
外殼會(huì)去掉,即case undefined of _ -> 1
粹湃,_
可以匹配所有恐仑,undefined
不求值
ghci> case N undefined of N _ -> 1
1
運(yùn)行時(shí),D _
來(lái)匹配undefined
的求值結(jié)果为鳄,undefined
要求值裳仆,發(fā)生錯(cuò)誤
ghci> case undefined of D _ -> 1
*** Exception: Prelude.undefined
運(yùn)行時(shí),N
外殼會(huì)去掉孤钦,即case undefined of _ -> 1
歧斟,_
可以匹配所有记某,undefined
不求值
ghci> case undefined of N _ -> 1
1
5. typeclass
類型類提取了相似的運(yùn)算
類型類的實(shí)例是一個(gè)類型構(gòu)造器,這個(gè)類型構(gòu)造器構(gòu)造的類型具有類型類指定的運(yùn)算
注:
類型類的實(shí)例构捡,是一個(gè)類型構(gòu)造器
類型構(gòu)造器液南,可以是零元類型構(gòu)造器(具體的類型),也可以帶參數(shù)
例如:
class BasicEq a where
isEqual :: a -> a -> Bool
其中勾徽,BasicEq
類型類滑凉,定義了isEqual
函數(shù)
指定類型構(gòu)造器Bool
(零元類型構(gòu)造器,即具體的類型)是BasicEq
類型類的實(shí)例
于是喘帚,isEqual
就具體化為isEqual :: Bool -> Bool -> Bool
instance BasicEq Bool where
isEqual True True = True
isEqual False False = True
isEqual _ _ = False
6. Monad
Monad是一個(gè)類型類
針對(duì)一般化的鏈?zhǔn)讲僮鞒╂ⅲx了>>=
和return
兩種運(yùn)算
class Monad m where
-- chain
(>>=) :: m a -> (a -> m b) -> m b
-- inject
return :: a -> m a
其中,Monad類型類的實(shí)例吹由,是一個(gè)單參類型構(gòu)造器
注:
m a
類型的值若未,通常稱之為action
有時(shí)候,返回action的函數(shù)倾鲫,也稱之為action
instance Monad Maybe where
Nothing >>= f = Nothing
Just a >>= f = f a
return = Just
其中粗合,>>=
具體化為了(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
return
具體化為了return :: a -> Maybe a
f
的類型是f :: a -> Maybe b
Nothing
和Just
是Maybe a
類型的值構(gòu)造器
data Maybe a = Nothing
| Just a
注:
Monad還定義了兩種操作>>
和fail
(>>) :: m a -> m b -> m b
a >> f = a >>= \_ -> f
>>
并不關(guān)心a
的執(zhí)行結(jié)果,只是進(jìn)行順序調(diào)用
fail :: String -> m a
fail = error
7. do語(yǔ)法塊
do語(yǔ)法塊會(huì)在編譯時(shí)轉(zhuǎn)換為>>=
乌昔,>>
和return
形式
(1)單個(gè)action
doNotation1 =
do act
translated1 =
act
(2)多個(gè)action
doNotation2 =
do act1
act2
{- ... etc. -}
actN
translated2 =
act1 >>
do act2
{- ... etc. -}
actN
finalTranslation2 =
act1 >>
act2 >>
{- ... etc. -}
actN
(3)帶有<-
的action
doNotation3 =
do pattern <- act1
act2
{- ... etc. -}
actN
translated3 =
let f pattern = do act2
{- ... etc. -}
actN
f _ = fail "..."
in act1 >>= f
(4)let
doNotation4 =
do let val1 = expr1
val2 = expr2
{- ... etc. -}
valN = exprN
act1
act2
{- ... etc. -}
actN
translated4 =
let val1 = expr1
val2 = expr2
valN = exprN
in do act1
act2
{- ... etc. -}
actN
8. State Monad
為原有類型定義一個(gè)新的標(biāo)識(shí)
newtype State s a = State {
runState :: s -> (a, s)
}
其中隙疚,類型構(gòu)造器是State
字段的類型是s->(a,s)
是一個(gè)函數(shù)
字段訪問器是runState
注:
因?yàn)?code>State是一個(gè)雙參類型構(gòu)造器,
所以State s
是一個(gè)單參類型構(gòu)造器
runState
的類型是runState :: State s a -> s -> (a, s)
指定State s
是Monad類型類的實(shí)例
instance Monad (State s) where
...
注:
Monad類型類的實(shí)例磕道,是一個(gè)單參類型構(gòu)造器供屉,
所以,State s
是Monad類型類的實(shí)例溺蕉,State
不是
returnState :: a -> State s a
returnState a = State $ \s -> (a, s)
bindState :: State s a -> (a -> State s b) -> State s b
bindState m k = State $ \s -> let (a, s') = runState m s
in runState (k a) s'
其中伶丐,m
的類型是m :: State s a
k
的類型是k :: a -> State s b
runState
的類型是runState :: State s a -> s -> (a, s)