记录访问者的语法默认值

时间:2012-01-18 19:27:50

标签: haskell record default-value

就在我刚才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(无论fooAge)。我可以想到几种方法来实现这一目标,但它们要求我

  1. 使用智能构造函数,理论上允许Skirt Male foo但不暴露构造函数
  2. 定义我自己的gender函数
  3. 对于#1,通过不暴露模块中的构造函数,我有效地阻止了模块的用户利用记录语法。对于#2,我必须完全放弃记录语法,或者定义一个额外的函数gender',这再次击败了记录语法。

    有没有办法既利用记录语法,又为我的一个构造函数提供“默认”,不可更改的值?我对非记录语法解决方案(也许是镜头?)持开放态度,只要它们同样优雅(或更多)。

2 个答案:

答案 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}} })。