——以下译自《Real World Haskell》P157
<u></u>newtype
关键字,用来给已存在的类型,设置一个新的身份。
<u></u>newtype
比data
限制更多,newtype
只能有一个值构造器,且这个值构造器只能有一个字段。
反例:
-- no fields
newtype TooFew = TooFew
-- more than one field
newtype TooManyFields = Fields Int Int
-- more than one constructor
newtype TooManyCtors = Bad Int | Worse Int
除此之外,data
和newtype
还有另外一个区别。
使用data
创建的类型,在运行时具有簿记的花销,因为要跟踪该类型的值是由哪个值构造器创建的。
而newtype
创建的类型,因为只能有一个值构造器,所以没有这种负担,这使得在运行的时候,无论在时间还是空间上都更有效率。
因为newtype
的值构造器,只用于编译时,在运行时是不存在的。
所以,对于undefined
进行模式匹配时,newtype
定义类型的值和data
定义类型的值,表现方式是不同的。
我们使用data
来定义一个DataInt
类型,使用newtype
来定义一个NewtypeInt
类型
data DataInt = D Int
deriving (Eq, Ord, Show)
newtype NewtypeInt = N int
deriving (Eq, Ord, Show)
我们知道,undefined
如果在运行时被求值,就会导致程序崩溃。
ghci> undefined
*** Exception: Prelude.undefined
[类型DataInt,情况1]
由于Haskell的模式匹配是惰性的,所以如果undefined
不需要被求值时,程序不会崩溃。
ghci> case D undefined of D _ -> 1
1
[类型DataInt,情况2]
但是,当undefined
必须求值才能完成模式匹配时,程序就会崩溃。
ghci> case undefined of D _ -> 1
*** Exception: Prelude.undefined
我们将以上DataInt
类型的值构造器,换成NewtypeInt
类型的值构造器N
,结果如下:
[类型NewtypeInt,情况1],与[类型DataInt,情况1],相同
ghci> case N undefined of N _ -> 1
1
[类型NewtypeInt,情况2],与[类型DataInt,情况2],不同
ghci> case undefined of N _ -> 1
1
这里程序并不会崩溃,因为在运行时,已经没有NewtypeInt
类型的值构造器N
了。
对“N _
”进行匹配,事实上就是对“_
”进行匹配。
而“_
”总是会满足匹配条件,所以undefined
是不需要被求值的。
网友评论