Haskell 随笔三 代数数据类型
本文记录一下个人学习Haskell的一些随笔,记录一下学习Haskell过程中的一些有趣的东西
Haskell语言的思维可能颠覆绝大多数鱼友对编程语言的认知
因为是随笔,可能继续更新也可能不继续更新
往期帖子
随笔三 ADTs(Algebraic Data Types)
代数类型是一个复合型的数据类型,将多个数据组成一个类型的数据类型,通常这个数据类型在一般编程语言语法上支持的就是这两种sum type
和product type
即和类型还有积类型,不过其他的代数类型基本也都是由和积两个类型进行抽象的
在Haskell中类型,值,运算符其实都是函数,但是为了照顾鱼油方便理解将会继续按类型,值,运算符等的说法来讲
和类型(sum type)
和类型是一个值的集合类型,一个和类型中的值都是互斥的也就是值都并不相同且每个值都是唯一的,它们的类型都是相同的,都是归属为一个和类型,来一个例子方便理解
用和类型来抽象货币这个事务
不同的国家有不同的货币,所以货币是一个集合,它的值是美元(USD)、欧元(EUR)、英镑(GBP)、人民币(CNY),也就是说货币这个概念在现在被定义出来的时候代表的是这些值
这时USD、EUR、GBP、CNY
这些值都是Currency
类型,每个值都不相同,它们都是唯一的
当使用USD
这个值的时候对于USD
来说,Currency
只有USD
它一个值,对于EUR、GBP、CNY
也是同理
因此可以把和类型叫做or
,Currency
的值是USD
或者是EUR
或者是GBP
或者是CNY
也就是说货币(Currency)是由美元(USD)、欧元(EUR)、英镑(GBP)、人民币(CNY)这几个值形成的集合
是不是和枚举类型很像?其实枚举类型就是sum type的一种
积类型(product type)
积类型则是多个类型组成的集合类型,多个类型抽象的复杂类型,也是一个最常用的的类型,像元组,结构体,类,数组,map,树等等都是积类型的抽象
接着和类型的抽象,用积类型来抽象钱数这个事务
在Haskell中data Money
表示的是这个类型的名字,等号后面的Money Int Currency
中的Money
表示的是这个类型的构造子也可以叫做构造函数,为了方便区分这里会给这个类型重新命名为Money'
Money
后面跟着的Int
和Currency
是两个参数的类型,也就是表明Money
这个构造子有两个参数分别是Int
和Currency
类型
一个钱的数量得知道是美元还是人民币毕竟它俩的汇率不一样购买力也不一样,所以实例化是这样的
可以看到钱这里实例化了20块钱美元和20块钱人民币
Money'
这个类型并不像Currency
和类型那样,在集合中选出一个值来代表类型,而是Int
和Currency
一起才能代表Money
类型,所以积类型可以叫做and
,Int
和Currency
组合成了Money'
如果想要单独获取某个参数的值则需要手动创建函数利用匹配模式进行匹配获取,我把这些函数称为成员函数(字段函数)
记录(record)
虽然Money Int Currency
这样的构造子是可以到抽象,但是一个事务的特征更加多的话将会变得很难区分,并且会手动创建非常多的成员函数,比如抽象一个银行的用户信息,银行的用户信息需要用户名、性别、电话、年纪还有存款
无法一眼确定哪个是用户名、性别、电话等等信息,还得手动创建相应的成员函数
所以应对这个需求Haskell有一个语法可以自动给User的每个参数带有自己的函数
给每个成员声明好类型这样Haskell的编译器会自动帮忙注册这些成员的函数,这样只需要把User传给相应的成员函数就可以得到相应的字段了
Haskell对于记录还有更新的语法,使用大括号并且标明哪个成员的名称来进行更新,User本来是一个空的数据结构,使用大括号是在对User这个空的数据结构进行更新,从空的值更新到大括号里对应的值
也可以用来局部的更新
但是请记住,更新并不是在原有的数据上进行更新,而是在原有的数据上进行新建,把你更新的部分重新创建一个新的数据
就像这样
User "ida" "man" "1234567" 999 (Money 9999999 CNY)
更新的时候
User "bulabula" "man" "1234567" 999 (Money 9999999 CNY)
再一次进行实例化,最终得到相应的值
随笔三 结语
代数数据类型并不是在Haskell的专属在其他语言里也是存在的,c,java,rust,go等等语言也都有sum type
还有product type
,比如和类型对应的枚举类型,go中的sum type
则需要空接口的断言配合,积类型对应的结构体,元组等等,还有记录也是可以使用积类型进行抽象,代数数据类型还有其他常用的类型不过这些基本都是会使用和类型积类型来进行抽象,代数类型也不是死板的,也会经常有一些混合,比如树的定义,如下
拥有多个值Leaf
还有Node
,其中的Node
构造子还有多个参数,即属于和类型也属于积类型
也还有递归类型,比如一个链表的定义
等等等等,感兴趣的可以自己自行查找资料
最后,你可能有一个疑问,和不是几个值的相加,积不是几个值的相乘嘛?但是看上面这些的描述跟相加相乘基本都不搭边,为什么还要叫做和类型还有积类型呢?
这个其实比较抽象,和类型是多个值组和而成的类型中的“和”,所以叫做和类型
而积类型则是因为笛卡尔积x\times y\times z多个类型的乘积
用结构体来表示(类同理)就能理解了
typedef struct {
int x
long y
char z
}
所以这个“积”是笛卡尔积的积
附上python使用代数数据类型实现的二叉树方便不会Haskell的鱼油进行理解
定义一个可比大小的类型接口
二叉树实现
最后的最后再挖个坑,本文开头的时候说了Haskell中一切都是函数,类型、值、运算符,甚至函数的定义本身也是个函数。如果有人想看以后会找机会说😋
不亏是布拉院士啊
牛的
牛逼