我已经定义了以下记录:
data Option = Option { a :: Maybe String,b :: Either String Int } deriving (Show)
有没有办法强制执行,当一个没有,b必须是一个左,当一个只是,b必须是一个权利?也许是幻影类型,还是别的?或者我必须将整个东西包装在一个或者任何一个String(String,Int)?
您应该使用两个可能的形状的两个构造函数:
data Option = NoA String | WithA String Int
当然,你应该给他们更好的名字,根据他们的代表. Phantom类型绝对是在这里过度的,我建议避免任何一个 – 左和右不是非常自我记录的构造函数名称.
如果将b字段的两个分支都解释为表示相同的数据是有意义的,那么您应该定义一个反映此解释的函数:
b :: Option -> MeaningOfB b (NoA s) = ... b (WithA t n) = ...
如果您的字段保持不变,无论选择什么,都应该创建一个新的数据类型,并将其包含在这两个构造函数中.如果您使每个构造函数成为记录,您可以在每个构造函数中给公共字段同名,以便您可以从任何Option值中提取它,而无需对其进行模式匹配.
基本上,考虑字符串不存在意味着什么:它对其他领域有什么变化,什么保持不变?无论在各自的构造函数中有什么变化;任何保持同样的东西都应该被分解成自己的类型. (这是一个很好的设计原则!)
如果您来自OOP背景,您可以从构成而不是继承的推理来思考这一点 – 但是尽量不要把类推得太远.