Haskell Algebraic datatypes

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 ]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容