就在我刚才writing up an answer,我遇到了一个有趣的问题:
data Gender = Male | Female
deriving (Eq, Show)
data Age = Baby | Child | PreTeen | Adult
deriving (Eq, Show, Ord)
data Clothing = Pants Gender Age
| Shirt Gender Age
| Skirt Age -- assumed to be Female
deriving (Show, Eq)
假设我希望用记录语法编写最终数据类型:
data Clothing = Pants {gender :: Gender, age :: Age}
| Shirt {gender :: Gender, age :: Age}
| Skirt {age :: Age}
deriving (Show, Eq)
问题是,我希望gender $ Skirt foo
始终评估为Female
(无论foo
是Age
)。我可以想到几种方法来实现这一目标,但它们要求我
Skirt Male foo
但不暴露构造函数gender
函数对于#1,通过不暴露模块中的构造函数,我有效地阻止了模块的用户利用记录语法。对于#2,我必须完全放弃记录语法,或者定义一个额外的函数gender'
,这再次击败了记录语法。
有没有办法既利用记录语法,又为我的一个构造函数提供“默认”,不可更改的值?我对非记录语法解决方案(也许是镜头?)持开放态度,只要它们同样优雅(或更多)。
答案 0 :(得分:0)
有没有办法既可以利用记录语法,又可以为我的一个构造函数提供“默认”,不可更改的值?
在没有令人信服的反例的情况下,答案似乎是“不”。
答案 1 :(得分:0)
是的,类型和数据之间存在紧张关系......顺便说一下,线条有多薄。
实际答案是使用Haskell Wiki中指示的默认实例。它确实回答了您的确切问题,因为您必须放弃直接使用构造函数。
因此,对于您的示例,
data Age = Baby | Child | PreTeen | Adult | NoAge
data Clothing = Pants {gender :: Gender, age :: Age}
| Shirt {gender :: Gender, age :: Age}
| Skirt {gender :: Gender, age :: Age}
deriving (Show, Eq)
skirt = Skirt { gender=Female, age=NoAge }
然后,开发人员可以使用记录语法的复制和更新工具创建具有默认值的新实例
newSkirt = skirt { age=Adult }
和gender newSkirt
评估为Female
我想强调,这种方法会导致您在类型级别定义默认值,我认为这是一件好事(当然NoAge
构造函数是Nothing
的{{1}} })。