Haskell lesson:类型系统解读
来源:互联网 发布:淘宝消费贷款怎么申请 编辑:程序博客网 时间:2024/05/29 06:51
最近忙成狗了,吭哧吭哧终于把家搬完了,以后就长久的住在新家了,由于刚搬家,网线还没有接,又过了一个星期家里没网的日子。这一段时间又没时间好好整理haskell。甚是遗憾。从上次haskell实现Graham扫描算法到现在已经三周有余,这次分析一下haskell类型系统。
首先回忆一下C语言是怎么构造新类型的。
struct Test { int index;#define NAME_LEN 32 char name[NAME_LEN]; void (*get_name)(struct Test *);};
这就是典型的C语言构造新类型的方法,即所谓的结构体。诸如此类的还有枚举类型、联合体。结构体定义了一个类型名字,成员都有其名字,并且根据名字访问到各个成员。
一、代数数据类型(algebraic data type)与类型构造子(data constructor)
定义类型: data TypeName = TypeConstructor [param] [| TypeConstructor [param]]
其中param可有可无,但是要注意如果param存在,那么其肯定是一种类型。比如data Test = Test Int
,表示传给一个Int类型的参数给类型构造子Test,这时候在ghci中执行:t Test
可以看到
*Main> :t TestTest :: Int -> Test
还要注意第一个Test和第二个Test没有任何联系,第一个Test只是表示该类型名字叫Test,在代码中实际使用的是第二个Test(也就是类型构造子)。
二、类型解构与模式匹配
在前面实现Graham扫描算法的例子中,我们使用了很多的函数,基本上都是通过模式匹配实现的。再举个例子,譬如求和函数:
sum (x:xs) = x + sum xssum [] = 0
在第一次看到行如(x:xs)的时候,可能会有疑问–为什么有个括号?其实(x:xs)中的冒号(:)是一个类型构造子。在ghci中输入:t (:)
可以看到
*Main> :t (:)(:) :: a -> [a] -> [a]
(:)就是用来构造列表的,而形如[1,2,3]的构造方式其实等价于(1:(2:(3:[])))。
说到这里,其实基本上就清楚了,模式匹配其实就是在对类型进行解构,使用的方法就是通过类型构造子的规定按照顺序进行参数匹配。
现在对前面定义的Test类型进行解构,在ghci中输入如下:
*Main> data Test=Test Int*Main> getTest (Test a)=a*Main> getTest (Test 10)10
三、类型匹配
通过模式匹配得到类型之后,haskell还会进一步检查类型是否匹配。
关于类型匹配,这里可以先简单实验一下,在ghci中输入如下:
*Main> (\x->x+1)12*Main> *Main> *Main> (\x->x+1)[]<interactive>:37:1: error: • Non type-variable argument in the constraint: Num [a] (Use FlexibleContexts to permit this) • When checking the inferred type it :: forall a. Num [a] => [a]*Main>
第一次输入一个lambda表达式紧跟一个数1,这时候ghci给出了我们想要的结果2。当第二次我们入[]时,报的错误有点意思。
类型错误,这里有两点信息:
- lambda表达式是匿名函数,所以函数参数的匹配似乎和函数名字没有直接关系。
- 错误的直接原因显示为类型不匹配,其实haskell自己已经通过类型系统推导出了当前输入x的类型是Num [a], 而实际上运算+期待的参数是Num a,所以产生类型错误。
类型匹配就是由haskell的类型推导系统完成的。
四、newtype/type/data
前面都是关于自定义类型data type的分析,除了data关键字以外,haskell还提供newtype和type关键字。type只是给已有的类型取一个别名,类型上并不会改变,编译器认为两者其实是一个类型。而newtype则不同,他会新定义一个类型,但是又有所限制。newtype只能有一个值构造器,而且构造器恰好只有一个字段,只存在于编译阶段。
五、代数数据类型实例
// algebraic data type without paramsdata Node = Node Int Char deriving (Show)// algebraic data type with paramsdata Node a = Node a deriving (Show)// record syntax, funcname :: data typedata Customer = Customer { customerID :: CustomerID , customerName :: String , customerAddress :: Address} deriving (Show)// recursion data type definitiondata Tree = Node Int Char (Tree) (Tree) | Empty deriving (Show)
- Haskell lesson:类型系统解读
- Haskell 笔记(三)类型系统
- haskell中的typeclass和类型系统
- haskell 类型
- Haskell Lesson:高阶函数
- Haskell 学习笔记 1 --环境搭建与类型系统(Haskell Tutorial 1--Getting start with Haskell)
- Haskell lesson:实现Graham扫描算法
- haskell的类型转换
- Haskell学习——类型
- Lesson 3:复合类型
- Haskell
- Haskell
- Android系统各种类型的service刨根解读
- Android系统各种类型的service刨根解读
- Haskell 笔记(四)函数系统
- Chapter 1: Lesson 1: 使用值类型
- 虚拟机网卡类型解读
- 字符串类型解读
- 第10章:网络编程:获取主机信息
- 第十一周——项目二—操作用邻接表存储的图
- Pixhawk组装中的一些BUG
- 利用Markdown创建表格
- 穷举二进制
- Haskell lesson:类型系统解读
- 开源的单点登录系统CAS入门
- C++必知必会——读书笔记(1)
- Computer Transformation UVA
- Unity Navmeshagent与飞行
- React高级指南(七)【React Without JSX】
- 计蒜客 最长公共子序列
- 1001. 害死人不偿命的(3n+1)猜想 (15)
- C语言进阶-第17讲:链表和数组的比较