——以下译自《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是不需要被求值的。








网友评论