Typeclass in Haskell筆記

April 19, 2017

代數數據類型

這樣定義一個類型:

data Name = Name String String

Name既是類型名,也是一個Value Constructor,一個類型通常有多個Value Constructor,不過按照習慣,如果一個類型僅僅有一個Value Constructor,那麼它的名字通常和類型名同名。

Value Constructor事實上只是一個函數,這也就決定了,不同的類型不能夠擁有相同名字的Value Constructor。

創建一個對象:

λ> Name "aries" "abel"
Name "aries" "abel" :: Name

有多個Value Constructor的例子:

data Shape = Rectangle Point Point
           | Circle Point Float
data Point = Point Float Float

創建一個Circle對象:

λ> Point 3 4
Point 3 4 :: Point
λ> Circle (Point 3 4) 3
Circle (Point 3 4) 3 :: Shape

Record

在代數類型裏面每個field所代表的意義不明確,並且如果需要得到某個field的值只能用模式匹配,非常繁瑣,所以這個時候Record就有用了:

data NamE = NamE { firstName :: String
                 , lastName :: String}

事實上,NamEName的類型是一樣的:

λ> :t NamE
NamE :: String -> String -> NamE
λ> :t Name
Name :: String -> String -> Name

創建一個Record對象:

λ> NamE "aries" "abel"
NamE "aries" "abel" :: NamE
λ> NamE { firstName = "aries", lastName = "abel" }
NamE { firstName = "aries", lastName = "abel" } :: NamE

可以看到,有兩種創建方法,第一種和代數類型的方法一樣,這是field必須和Record定義field的順序一致;另外一種可以指定每個field的名字,這個時候field的順序就不重要了。

另外,定義Record的時候,Haskell會默認生成一些accessor函數,也就是以這個Record的所有的field爲名字的函數。這樣我們就可以輕鬆取得Record的每個field。

λ> firstName (NamE "aries" "abel")
"aries"

Record同樣可以指定多個Value Constructor:

data Linux = Slackware { version :: Float
                       , desktopEnv :: String}
           | Gentoo { version :: Float
                    , desktopEnv :: String}

新建對象的方法和之前是一樣的:

λ> Slackware 14.2 "KDE 4"
Slackware 14.2 "KDE 4" :: Linux
λ> Gentoo 8.0 "Gnome 3"
Gentoo 8.0 "Gnome 3" :: Linux
comments powered by Disqus