所以我有一个这样的结构:
data Maybe a = Nothing | Just a
但我想要一个定义为的结构
data MaybeInt = Nothing | Just Int
有没有办法定义MaybeInt
using Maybe a
,如果是这样,如何定义?
有几种方法可以定义MaybeInt
. 我会陈述他们然后有一些评论。
直接的
data MaybeInt = NothingInt | JustInt Int
新型
newtype MaybeInt = MI (Maybe Int)
类型同义词
type MaybeInt = Maybe Int
清楚的
-- just use `(Maybe Int)` wherever you would write `MaybeInt`
评论
最常见的是,人们会使用简单的方法,因为大多数人都熟悉Maybe
并知道如何使用Just
和Nothing
匹配它。这使它对图书馆有好处——非常透明。类型同义词方法是一种常见的文档方法,但对于您的同义词基本上没用。它使得它foo :: Int -> Maybe Int
具有bar :: Int -> MaybeInt
相同的类型签名。这也意味着一旦有人知道MaybeInt === Maybe Int
他们可以使用Just
/Nothing
构造函数进行匹配。
newtype方法变得相当有趣。每次要使用type时,您都必须在此处开始“包装”和“展开”MI
构造函数。比较:MaybeInt
baz :: MaybeInt -> Bool
baz (MI Nothing) = False
baz (MI (Just int)) = True
这很好,因为如果您不导出 MI
,那么没有人将能够匹配MaybeInt
(尽管对其中发生的事情有很好的猜测)。这对于制作稳定的 API 非常有用。的另一个有趣的属性newtype
是你可以编写不同于's 内置的newinstance
的 s 。例如,您可以覆盖实例MaybeInt
Maybe
Monoid
instance Monoid MaybeInt where
mempty = MI Nothing
mi `mappend` (MI Nothing) = mi
_ `mappend` mi = mi
这与包含s 的Last a
内置 newtype相同。Data.Monoid
Maybe a
最后,我们得到了完整的data
实例。它更冗长、更容易出错、速度稍慢(因为编译器必须跟踪新的、唯一的数据类型),并且需要人们学习新的构造函数。对于如此明显相同Maybe Int
的功能,根本没有理由使用它。