Data declarations review
data Bool = False | True
data [] a = [] | a : [a]
- 关键字 data 声明数据类型
- Bool 类型构造器,但是没有参数
- 等号把数据构造器付给类型构造器
- False True 是数据构造器但是没有接受任何参数,称为
nullary constructor
- | 表示它是 sum type,可以分开逻辑它有什么类型的值
- [] a 类型构造器,并且接受一个参数
当我们在讲数据声明的时候,是讲它整个类型的定义,类型可以有一个或多个构造器,构造器可以接受一个或多个参数,Bool 有两个构造器,两个构造器都不接受参数
Data and type constructors
在 Haskell 中有两种构造器,一种是类型构造器,一种是数据构造器, 我们可以在常量和构造器中做区别,类型和数据构造器如果没有接受参数,就是常量,他们只能保持那个固定的值,例如 Bool, Bool 是一个类型常量,True 和 False 也是常量,因为他们没有接受参数
data Trivial = Trivial'
data UnaryTypeCon a = UnaryValueCon a
- Trivial 就像一个常量,它不接受任何参数
- Trivial' 数据构造器也像一个常量值
- UnaryTypeCon 是一个类型构造器,并且接受一个参数,它等待一个参数,然后应用它
- UnaryValueCon 是一个数据构造器,接受一个参数它不像函数那样执行然后生成数据,这里它表现的想一个盒子,盒子里面有一个值
Type constructors and kinds
data [] a = [] | a : [a]
这里必须先应用一个类型到 a,然后才能获取到正确类型的数据,Kinds 是类型的类型,kinds 在 Haskell 中用 * 来表示。* -> * 就像一个函数,它等待应用一个类型,就可以生成 * 了。
Prelude> let f = not True
Prelude> :t f
f :: Bool
Prelude>
我们可以用 :k
来查看类型构造器的签名
Prelude> :k Bool
Bool :: *
Prelude>
Prelude> :k []
[] :: * -> *
Prelude>
Data constructors and values
data PugType = PugData
data HuskyType a = HuskyData
data DogueDeBordeaux doge =
DogueDeBordeaux doge
- PugType 是类型构造器,但是他没有接受参数,我们可以把他认为是类型常量
- PugData 是类型 PugType 的数据构造器,它是一个常量值,当任何函数需要 PugType 类型,可以明确的知道他的值是 PugData
- HuskyType 是一个类型构造器,他接受一个参数,有一个数据构造器
- HuskyData 是 HuskyType 的一个数据构造器,这里的 HuskData 是一个常量值,就和 PugData 一样
- DogueDeBordeaux 是一个类型构造器,它有一个类型参数
- DogueDeBordeaux 是一个单独的数据构造器,它和类型构造器是同名的,但是他们不是同一个东西。
What's a type and what's data?
类型是静态的并在编译的时候解析,类型是在运行之前已经确定的,data 是在运行时工作的
Exer
data Price =
Price Integer deriving (Eq, Show)
data Manufacturer =
Mini
| Mazda
| Tata
deriving (Eq, Show)
data Airline =
PapuAir
| CatapultsRUs
| TakeYourChancesUnited
deriving (Eq, Show)
data Vehicle = Car Manufacturer Price
| Plane Airline
deriving (Eq, Show)
isCar :: Vehicle -> Bool
isCar (Car _ _) = True
isCar _ = False
isPlane :: Vehicle -> Bool
isPlane (Plane _) = True
isPlane _ = False
areCars :: [Vehicle] -> [Bool]
areCars = foldr f []
where f = (\a b -> (if (isCar a) then True else False) : b)
areCars' :: [Vehicle] -> [Bool]
areCars' = map isCar
getManu :: Vehicle -> Manufacturer
getManu (Car m _) = m
Data constructor arities
Arity
指的是一个函数或者构造器接受几个参数,一个函数接受零个参数叫做 nullary
Data constructors 接受一个参数叫做 unary
, data constructors 接受多于一个参数以上的参数叫做 products
-- nullary
data Example0 =
Example0
deriving (Eq, Show)
-- unary
data Example1 =
Example1 Int
deriving (Eq, Show)
-- product
data Example2 =
Example Int String
deriving (Eq, Show)
What makes these datatypes algebraic?
代数数据类型在 Haskell 中是有代数性质的,因为我们可以使用 sum product 这两种基本的操作来描述它,为什么可以用 sum 和 product 来描述它们,是因为它们可以用 cardinality(基数)
来总结它们
cardinality 是 datatype 的所有可能的情况,它可以是 0,也可以是无限种情况,知道有多少可能值出现在某种类型,可以帮助更加的理解你的程序。
Unary constructors
如果是 unary constructor
它的 cardinality
通常和它所含的 type 是一样的, 如下
data Goats = Goats Int deriving (Eq, Show)
Product types
Product types 类似于 C 语言的结构体,它就像用多个类型的值来表达一个单独的数据结构。元组就是一个 Product types
(,) :: a -> b -> (a, b)
Record syntax
Records
是 Haskell 提供给 product types 的一个额外的语法
data OperatingSystem =
GnuPlusLinux
| OpenBSDPlusNevermindJustBSDStill
| Mac
| Windows
deriving (Eq, Show)
data ProgLang =
Haskell
| Agda
| Idris
| PureScript
deriving (Eq, Show)
data Programmer =
Programmer {
os :: OperatingSystem,
lang :: ProgLang
}
deriving (Eq, Show)
allOperatingSystems :: [OperatingSystem]
allOperatingSystems =
[
GnuPlusLinux,
OpenBSDPlusNevermindJustBSDStill,
Mac,
Windows
]
allLanguages :: [ProgLang]
allLanguages =
[
Haskell,
Agda,
Idris,
PureScript
]
allProgrammers :: [Programmer]
allProgrammers = [ Programmer { os = o, lang = l }| o <- allOperatingSystems, l <- allLanguages ]