Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell "dependent" fields of a record?

Tags:

haskell

record

I've got the following record defined:

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

Is there anyway for me to enforce that when a is Nothing, b must be a Left and when a is Just, b must be a Right? Maybe with phantom types, or something else? Or must I wrap the whole thing inside of an Either and make it Either String (String, Int) ?

like image 697
Ana Avatar asked Dec 24 '11 17:12

Ana


1 Answers

You should just use two constructors for the two possible shapes:

data Option = NoA String | WithA String Int

Of course, you should give them better names, based on what they represent. Phantom types are definitely overkill here, and I would suggest avoiding EitherLeft and Right are not very self-documenting constructor names.

If it makes sense to interpret both Either branches of the b field as representing the same data, then you should define a function that reflects this interpretation:

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

If you have fields that stay the same no matter what the choice, you should make a new data type with all of them, and include it in both constructors. If you make each constructor a record, you can give the common field the same name in every constructor, so that you can extract it from any Option value without having to pattern-match on it.

Basically, think about what it means for the string not to be present: what does it change about the other fields, and what stays the same? Whatever changes should go in the respective constructors; whatever stays the same should be factored out into its own type. (This is a good design principle in general!)

If you come from an OOP background, you can think about this in terms of reasoning with composition instead of inheritance — but try not to take the analogy too far.

like image 147
ehird Avatar answered Nov 03 '22 15:11

ehird