自定义类型和类型类


In [1]:
-- 方法1 使用data定义类型
-- 左边为类型名, 右边有类型值构造器`
data Bool = False | True

In [2]:
-- 构造自己的类型
data Shape = Circle Float Float Float | Rectangle Float Float Float Float

In [3]:
:t Circle


Circle :: Float -> Float -> Float -> Shape

In [4]:
:t Rectangle


Rectangle :: Float -> Float -> Float -> Float -> Shape

In [5]:
-- 值构造器类似函数调用

In [7]:
-- 这里Shape是类型,而Shape/Circle不是
area :: Shape -> Float
area (Circle _ _ r) = pi * r ^ 2
area (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)

In [9]:
area $ Circle 10 20 10


314.15927

In [10]:
area $ Rectangle 0 0 100 100


10000.0

In [11]:
-- 实现show类型类才能显示在终端,类似__str__方法
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
    deriving (Show)

In [12]:
Circle 10 20 5


Circle 10.0 20.0 5.0

In [13]:
Rectangle 50 230 60 90


Rectangle 50.0 230.0 60.0 90.0

In [14]:
-- 值构造器本质是函数,所以可以部分应用
map (Circle 10 20) [4..7]


[Circle 10.0 20.0 4.0,Circle 10.0 20.0 5.0,Circle 10.0 20.0 6.0,Circle 10.0 20.0 7.0]

In [17]:
-- point类型,类型组合
-- 值构造器可以和类型同名
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)

In [18]:
area :: Shape -> Float
area (Circle _ r) = pi * r ^ 2
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)

In [19]:
area (Rectangle (Point 0 0) (Point 100 100))


10000.0

In [20]:
area (Circle (Point 0 0) 24)


1809.5574

In [21]:
nudge :: Shape -> Float -> Float -> Shape
nudge (Circle (Point x y) r) a b = Circle (Point (x+a) (y+b)) r
nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = Rectangle (Point (x1+a) (y1+b)) (Point (x2 + a) (y2 + b))

In [23]:
nudge (Circle (Point 34 34) 10) 5 10


Circle (Point 39.0 44.0) 10.0

In [25]:
baseCircle :: Float -> Shape
baseCircle r = Circle (Point 0 0) r

In [26]:
baseRect :: Float -> Float -> Shape
baseRect width height = Rectangle (Point 0 0) (Point width height)

In [27]:
nudge (baseRect 40 100) 60 23


Rectangle (Point 60.0 23.0) (Point 100.0 123.0)

In [28]:
-- 模块中可以导出类型, 方便外部使用
-- module Shapes (Shape(..), Point(..), area, nudge) where
-- Shape(..)导出shape所有值构造器, 等价于Shape(Circle, Rectangle)
-- Shape会不导出值构造器.

-- 也可不导出,抽象度更高. 但无法使用类型匹配

记录语法. 类似erlang记录


In [30]:
-- 第二种数据类型创建方法
-- 非纪录语法
data Person = Person String String deriving (Show)
let guy = Person "Buddy" "Frink"
guy


Person "Buddy" "Frink"

In [31]:
firstName :: Person -> String
firstName (Person first _) = first

In [32]:
lastName :: Person -> String
lastName (Person _ lastname) = lastname

In [33]:
firstName guy


"Buddy"

In [35]:
lastName guy


"Frink"

In [36]:
-- 记录语法, 可以直接通过字段取值,类型ruby extends
-- show更好看
data Person = Person {firstName :: String
                      , lastName :: String
                      , age :: Int } deriving (Show)

In [37]:
:t age


age :: Person -> Int

In [38]:
data Car = Car String String Int deriving (Show)

In [39]:
:t Car


Car :: String -> String -> Int -> Car

In [40]:
Car "Ford" "Must" 1978


Car "Ford" "Must" 1978

In [44]:
-- XXX errors
data Car  Car { company :: String
                 , model :: String
                 , year :: Int } deriving (Show)


Parse error (line 1, column 6): Unexpected type ‘Car’
In the data declaration for ‘=’
A data declaration should have form
data = a b = ...

In [45]:
:t Car


Car :: String -> String -> Int -> Car

In [47]:
-- 类型参数, 类型可以取参数产生新类型
-- Maybe变为类型构造器,
data Maybe a = Nothing | Just a

In [48]:
Just 3 :: Maybe Int


Unshowable:Maybe IntNo instance for (Show (Maybe Int)) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it

In [49]:
-- 列表是类型参数

In [50]:
Just "Haha"


Unshowable:Maybe StringNo instance for (Show (Maybe String)) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it

In [51]:
-- 配合记录语法
data Car = Car { company :: a
                , model :: b
                , year :: c } deriving (Show)


Not in scope: type variable ‘a’


Not in scope: type variable ‘b’


Not in scope: type variable ‘c’

In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]: