【问题标题】:Haskell "dependent" fields of a record?Haskell记录的“依赖”字段?
【发布时间】:2011-12-24 17:11:24
【问题描述】:

我定义了以下记录:

data Option = Option {
    a    :: Maybe String,
    b    :: Either String Int
} deriving (Show)

我有没有强制要求当 a 是 Nothing 时 b 必须是 Left 而当 a 是 Just 时 b 必须是 Right?也许有幻影类型,或者其他什么?还是我必须将整个东西包裹在一个 Either 中并使其成为 Either String (String, Int)

【问题讨论】:

  • 我认为 Haskell 2010 在您以前的解决方案中没有任何允许这样做的东西。我建议使用Either String (String, Int),或同构类型,例如data Option = OptionA String | OptionB String Int,其中构造函数具有合理的名称。
  • 为了最好地回答这个问题,了解ab 所附的含义 很重要。为什么有时您没有a(例如Nothing)?为什么可以将b 表示为StringInt?你为什么要执行你所说的限制?这给我的初步印象是b 定义不明确。

标签: haskell record


【解决方案1】:

您应该只为两种可能的形状使用两个构造函数:

data Option = NoA String | WithA String Int

当然,您应该根据它们所代表的内容给它们起更好的名称。幻像类型在这里绝对是矫枉过正,我建议避免 EitherLeftRight 不是非常自我记录的构造函数名称。

如果将 b 字段的两个分支都解释为表示相同的数据是有意义的,那么您应该定义一个反映这种解释的函数:

b :: Option -> MeaningOfB
b (NoA s) = ...
b (WithA t n) = ...

如果您的字段无论选择什么都保持不变,那么您应该使用所有这些字段创建一个新的数据类型,并将其包含在两个构造函数中。如果将每个构造函数都设为记录,则可以在每个构造函数中为公共字段赋予相同的名称,这样就可以从任何 Option 值中提取它,而无需对其进行模式匹配。

基本上,想想字符串不存在意味着什么:它对其他字段有什么改变,什么保持不变?相应的构造函数中应该进行的任何更改;任何保持不变的东西都应该被分解成它自己的类型。 (总的来说,这是一个很好的设计原则!)

如果您来自 OOP 背景,则可以从组合推理而非继承的角度来考虑这一点——但请不要把类比走得太远。

【讨论】:

    猜你喜欢
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多