我已经定义了以下记录:
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)
吗?
答案 0 :(得分:18)
你应该只为两种可能的形状使用两个构造函数:
data Option = NoA String | WithA String Int
当然,你应该根据他们的代表给他们更好的名字。幻影类型肯定是矫枉过正的,我建议避免Either
- Left
和Right
不是非常自我记录的构造函数名称。
如果将b字段的两个分支都解释为表示相同的数据是有意义的,那么您应该定义一个反映这种解释的函数:
b :: Option -> MeaningOfB
b (NoA s) = ...
b (WithA t n) = ...
如果您的字段保持不变,无论选择何种,您都应该为所有字段创建一个新的数据类型,并将其包含在两个构造函数中。如果您将每个构造函数都设为记录,则可以在每个构造函数中为公共字段指定相同的名称,以便您可以从任何Option
值中提取它,而无需对其进行模式匹配。
基本上,考虑字符串不存在的意味着什么:它对其他字段有什么改变,什么保持不变?各个构造函数应该发生什么变化;无论什么样的停留都应该考虑到它自己的类型。 (这一般是一个很好的设计原则!)
如果你来自OOP背景,你可以在构思而不是继承的推理方面考虑这一点 - 但是尽量不要把这个类比推得太远。