强大的类型系统是Haskell的一个非常大的优势。
Haskell所有表达式类型在编译期判断。这样的话,可以使得代码
更加安全,比如说,拿一个整数和一个字符串进行除法运算是没办法进行的,那么在编译器就会直接报错,不会等到运行时程序崩溃才知道。Haskell与
Java不一样,Haskell能够进行类型推断(Type
Inference),也就是说,你不需要明确的说100是个数字,或者说是整型,编译期能推断出这是一个整型。
在GHCi中,我们可以使用:t 命令来检测一个表达式的类型。
Prelude> :t 'q'
'q' :: Char
Prelude> :t "aaa"
"aaa" :: [Char]
::操作符的含义是“具有…类型”。也就是说,根据上面的结果,我们
知道,字符q的类型是Char。一般来说,Haskell的类型的首字母都是大写,比如上面提到的Char,还有Bool或者Boolean。[]代表
List,[Char]代表元素类型为Char的List。()则代表 Tuple,('a','a')的类型是(Char,Char)。
1.显式类型声明
除了表达式之外,函数也是有类型的。我们在定义函数的时候,可以显式给函数声明其类型。我们在前面讲过一个去处字符串中大写字母的List Comprehension:
removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]
对于这样一个函数,很明显,其输入和输出都是字符串,也就是字符List,因此,我们可以这样声明函数的类型:
removeNonUppercase :: [Char]->[Char]
上面这个声明的含义是,函数removeNonUppercase接
收一个[Char]参数,并且返回一个[Char]。那怎么去指定一个接收多个参数的函数的类型呢?比如说有一个函数叫addThree,接收三个参数,
并且将这三个参数的值相加并且返回。我们可以这样指定addThree的函数类型:
addThree :: Int->Int->Int->Int
也就是说,最后一个会被当做返回值来解析,前面的都会被当做参数来解析。如果说你不知道你要写的函数到底应该是什么类型,你可以先把函数写出来,然后使用:t命令看看到底是什么类型,最后再补上函数类型指定。
2.常见的Haskell类型
类型
说明
Int
整型,但是能表示的整数有界限(达到一定程度就会溢出),效率更高
Integer
整型,能够表示的整数没有界限,效率低
Float
单精度浮点数
Double
双精度浮点数
Bool
布尔值,只有True和False两个值
Char
单个Unicode字符
Tuple
具体的Tuple类型取决于元素的类型和个数,理论上有无数Tuple类型,但是实际上Tuple最多只能有63个元素
3.类型变量(Type Variable)
有时候函数需要能够处理多种类型的数据,我们以head函数为例。首先看看head函数的类型:
Prelude> :t head
head :: [a] –> a
我们可以看到,函数head接收一个List作为输入,返回List
中的一个元素。但是这个元素到底是Char还是Int还是Bool并不重要。这个a是什么?我们说过所有的类型都是以大写字母打头的,a显然不是一种我们
所不知道的类型。a实际上就是我们这里说的类型变量的一个例子。类型变量能够允许函数以一种安全的方式操作多种类型,这一点类似于Java中的泛型。使用
类型变量的函数在Haskell中称为多态函数(Polymorphyc
function)。head函数的定义的含义是:head接收一个装任何元素的List,返回这种类型的一个值。
我们再看看fst函数的类型定义:
Prelude> :t fst
fst :: (a, b) –> a
这个函数接收一个pair,然后返回第一个元素,至于这个pair的元素可以是任何类型,这里的a,b都是类型变量。需要说明的是,这里的a和b虽然都是类型变量,但是不意味着他们一定是不同的类型。
4.Type Class
Type Class我也不知道该怎么翻译比较合适。Type
Class实际上是一种借口,它定义一些行为,当某个变量是这个Type Class的实例,那么它可以实现这个Type
Class所描述的行为。Type Class一般指定一组函数,一个变量是该Type
Class的实例,我们就需要确定这些函数对于这个变量本身有什么意义(也就是说这个变量要有自己的实现)。
定义相等性的Type Class就是一个很好的例子。很多类型都可以用==来看值是否相等。我们先看看==运算符的函数签名:
Prelude> :t (==)
(==) :: Eq a => a -> a –> Bool
实际上==是一个函数,基本上+,-,*以及几乎所有的运算符都是函
数。这里出现了一个新的符号=>,所有出现在这个符号之前的部分叫做class
constraint。这个函数类型的意思是:==函数接收两个值,他们同样属于类型Eq,函数最终返回一个Bool值。
Eq就属于Type
Class,它提供了判断值是否相等的接口。而这些值必须是相同类型才有比较的意义,这些值可以使Eq的实例。事实上,在标准的Haskell中,几乎所
有类型都是Eq的实例。需要特别指出的是,Type
Class并不是面向对象编程语言中的Class。下面我们一起看看Haskell中常见的集中Type Class:
Eq用来提供检测值是否相等的接口。它的两个实现是==和/=。这意
味着如果在一个函数的定义中出现了Eq class
constraint,那么这个函数的定义中肯定用到了==或者是/=。如果一种类型实现一个函数,他就要定义使用这个类型的值时,该函数到底做些什么。
我们看几个Eq实例进行相等性比较时的例子:
Prelude> 5 == 5
True
Prelude> 'q' == 'q'
True
Prelude> "Hello"=="hello"
False
Prelude> "Hello"=="Hello"
True
Prelude> pi == 3.14
False
我们可以看到,字符串的比较规则是遵循List的相等性比较,与Java中的比较引用是不一样的。
Ord是一种为那些可以将值放在某种顺序排列中的类型设计的Type Class。我们看看>函数的类型:
Prelude> :t (>)
(>) :: Ord a => a -> a –> Bool
>与==比较类似,都接收两个参数,然后返回一个Bool值。Ord Type Class涉及到了所有的比较函数:> < >= <=。
compare函数接收两个参数,这两个参数的类型都是Ord的实例,然后返回一个Ordering。Ordering是一个值可以是GT、LT或者EQ的类型,分别代表大于、小于和等于。我们看几个例子:
Prelude> "abcd" `compare` "bbcd"
LT
Prelude> "abcd" `compare` "abbd"
GT
Prelude> "abcd" `compare` "abcd"
EQ
类型是Show这个Type Class的实例的值可以被显示为字符串。对于所有属于Show这个Type Class的实例的类型来说,使用最多的函数式show(s小写)。我们看几个例子:
Prelude> show 3
"3"
Prelude> show True
"True"
Read可以看做是Show的反面。read函数接收一个字符串,然后返回一个类型是Read的实例的值。看例子:
Prelude> read "True" || False
True
Prelude> read "5"-2
3
Prelude> read "[1,2,3,4]" ++ [5]
[1,2,3,4,5]
目前为止都一切正常,我们再看一个例子:
Prelude> read "5"
<interactive>:30:1:
Ambiguous type variable `a0' in the constraint:
(Read a0) arising from a use of `read'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: read "5"
In an equation for `it': it = read "5"
当我们直接read "5"时,GHCi不知道该返回什么。我们之前的例子都将read返回的结果再参与某种运算,这样GHCi才好进行类型推断,这就是为什么read "5"没办法返回值的原因。我们看一下read函数的原型:
Prelude> :t read
read :: Read a => String –> a
我们看到,read函数接收String,但是返回一个类型是Read的实例的值。但是类型是Read实例的类型太多了,GHCi不知道到底选哪一种类型。这种情况下,我们可以使用类型注解(type annotation)。我们看例子是最直接的:
Prelude> read "5" :: Int
5
Prelude> read "5" :: Float
5.0
对于read来说还需要举一个例子:
Prelude> [read "True",False,True,False]
[True,False,True,False]
因为List中的每一个元素必须属于种类型,所以read "True"的返回值必须和其他元素类型一样,也就是Bool,这样,GHCi就知道该怎么返回值了。
Enum的实例是那种值有序的类型——他们的值可以被枚举。Enum
Type
Class最大的优势是可以在Ranges中使用其值。他们还定义了successors设predecessors,我们可以分别通过succ和
pred两个函数获得。Bool、Char、Ordering、Int、Integer、Float、Double是这个Type
Class的实例,我们看例子:
Prelude> ['a'..'e']
"abcde"
Prelude> [LT .. GT]
[LT,EQ,GT]
Prelude> [3 .. 5]
[3,4,5]
Prelude> succ 'B'
'C'
Prelude> pred 'B'
'A'
那些是Bounded实例的类型有一个上限值和一个下限值。分别可以使用minBound和maxBound查看:
Prelude> minBound::Int
-2147483648
Prelude> maxBound::Int
2147483647
minBound和maxBound的类型都是Bounded a=>a。准确来说,他们是多态常量。Tuple中所有元素类型都是Bounded的话,那么这个Tuple也被认为是Bounded的实例。
Num是数字Type Class,它的实例都是数字。所有的数字都是多态常量。也就是说我们可以将它制定成Num下属类型中的任何一种:
Prelude> 6::Int
6
Prelude> 6::Float
6.0
要成为Num Type Class的实例,这个类型必须要已经是Eq和Show Type Class的实例。
顾名思义,这种Type Class的实例类型就是用来存储浮点数的,就两种类型Float和Double。
包括Int和Integer两种。介绍两个函数fromIntegral和length,先看看两个函数的签名,再看看怎么使用:
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
Prelude> :t length
length :: [a] –> Int
Prelude> fromIntegral (length [1,2,3,4]) + 3.4
7.4
5.Tips
Type Class实际上是一个抽象的接口,所以一个类型可以是多种Type Class的实例,同样,一种Type Class有很多实例;
有时候一种类型必须先是一种Type Class的实例才会被允许成为另一个Type Class的实例。
分享到:
相关推荐
Haskell是一种纯函数式编程语言,它的命名源自美国数学家Haskell Brooks Curry,他在数学逻辑方面上的工作使得函数式编程语言有了广泛的基础。Haskell语言是1990年在编程语言Miranda的基础上标准化的,并且以λ演算...
了解haskell的最简单明了的教程,图文并茂,不过是英文的,大家斟酌好再下。
haskell趣学指南。haskell的入门书,十分适合初学者。
Haskell 学习资料,Learn you a Haskell.
Learn You A Haskell For Great Good Mar 2011.pdf
By working through 43 easy-to-follow lessons, you'll learn Haskell the best possible way—by doing Haskell! Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from ...
学习您的haskell笔记本:Jupyter改编的《 Learn a Haskell for Great Good!
本书是Learn you haskell for great good的中文电子版,方便阅读和查阅,是一本很好的工具书,对于Haskell入门来说很有帮助。
Haskell is one of the leading languages for teaching functional programming, enabling students to write simpler and cleaner code, and to learn how to structure and reason about programs. This ...
You will then learn about the basics of high frequency financial data mathematics as well as how to implement these mathematical algorithms in Haskell., You will also learn about the most popular ...
学习哈斯克尔 学习haskell 资料来源 向您了解Haskell( ) 学习Haskell( )
Learn_You_a_Haskell_for_Great_Good.pdf 英文版