阿男的小窝

View the Project on GitHub

Haskell中的Data Type

Haskell当中的class可以类比为Java当中的interface,而Haskell当中的data则可以类比为Java当中,实现interface的class(当然,这样的类比只是从语法的角度上帮助理解,其背后的设计理念还是有本质的不同的)。

下面的代码定义一个data,叫做MyType

data MyType = Foo

上面的定义当中,FooMyType的constructor。Java当中每一个class有自己的constructor,但是constructor的名字要和class的名字保持一致,而在Haskell当中没有这种限制(并且设计理念也不同,不是一个概念,下面展开讲)。

下面是我们定义的MyType的信息:

Prelude> :info MyType
data MyType = Foo 	-- Defined at <interactive>:1:1
Prelude> :info Int
data Int = GHC.Types.I# GHC.Prim.Int# 	-- Defined in ‘GHC.Types’

要注意的一点:Haskell要求类型的名称需要大写首字母,所以我们定义的type交做MyType,不能起名叫myType,这是Haskell的要求。

接下来我们看一下MyType的具体定义:

data MyType = Foo

这个Foo,被称为value constructor,它是一个函数:

Prelude> :t Foo
Foo :: MyType

可以看到Foo这个函数不接收任何参数,返回类型为MyType的数据。

我们试着使用Foo函数来创建一个MyType类型的数据:

Prelude> hahaha = Foo
Prelude> :info hahaha
hahaha :: MyType 	-- Defined at <interactive>:4:1
Prelude> :t hahaha
hahaha :: MyType

如上所示,我们调用Foo函数,创建了一个MyType类型的数据叫做hahaha

此外,Haskell还支持value constructor接收参数(可以类比为Java的class当中的constructor可以接收参数,是一个意思)。

比如我们可以定义一个叫做Book的type,这个type里面包括Book的一些信息,比如titleauthor,等等。我们定义Book如下:

data Book = Book String String

如上所示,我们定义了Book类型,然后定义了constructor叫做Book(data的constructor允许和data自身的名字重名),这个constructor接收两个String类型的参数。

我们可以用:t命令查询作为value constructor的Book函数的定义:

Prelude> :t Book
Book :: String -> String -> Book

可以看到,这个叫做Book的函数接收String, String参数,返回类型为Book的数据(前面的Book是函数,后面的返回值是Book类型)。

我们使用看看:

mybook = Book "Charlotte's Web" "E. B. White"

如上所示,我们创建了一个mybook数据,这本书的书名是Charlotte's Web,作者是E. B. White

但是我们怎么查看mybook里面的书名和作者呢?

为了解决这个问题,我们可以创建两个函数,一个叫做title,另一个叫做author

Prelude> title :: Book -> String; title (Book title _) = title
author :: Book -> String
Prelude> title :: Book -> String; author (Book _ author) = author

如上所示,我们定义了titleauthor两个函数,可以从Book类型中的数据取得titleauthor信息:

最后我们使用看看这两个函数:

Prelude> author mybook
"E. B. White"
Prelude> title mybook
"Charlotte's Web"
Prelude>

如上所示,我们通过上面的函数取得了mybook中的相关数据。