[Haskell] newtype

——以下译自《Real World Haskell》P157

newtype关键字,用来给已存在的类型,设置一个新的身份。
newtypedata限制更多,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

除此之外,datanewtype还有另外一个区别。
使用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是不需要被求值的。

你可能感兴趣的:([Haskell] newtype)