In Haskell, is there a way to limit a data type by the value of its components? I've drafted an example. Say you have a checkers game. A checker is either of the Black or White type.
data CheckerType = BlackChecker | WhiteChecker deriving (Eq)
data Checker = Checker CheckerType Int
The game board for a checker game contains a set of Black checkers and White checkers.
data GameBoard = GameBoard ([Checker]) ([Checker])
In the previous declaration, is there any way to enforce the Checkers in the first [Checker] to be of CheckerType black, and the second to be of the opposing type?
The simplest way to do something similar is to parameterize the Checker
type with what's called a "phantom type":
data Black
data White
Note that neither of these have any values. They only exist to indicate what color a Checker
is.
data Checker a = Checker Int
data GameBoard = GameBoard [Checker Black] [Checker White]
By the way, you don't need those parentheses in the GameBoard
declaration.
The downside to this approach is that the two colors are now different types, meaning you can't write a function that takes, say, a list of checkers of multiple colors, only a single color.
You could make the phantom types a bit more concrete in order to track allowed colors:
data Black = Black
data White = White
data Checker a = Checker a Int
type AnyChecker = Checker (Either Black White)
But this can quickly become a lot of hassle to use.
What I suspect you really want is a way to restrict the range of values allowed in one context without making it a completely different type in all contexts. Unfortunately, this isn't really possible in any straightforward fashion in Haskell.
It's a reasonable idea, and some languages do have similar features. Supporting distinctions like this in a generalized way is not simple to add to Haskell's existing type system without collateral damage, though, such as making type inference less robust, even in code not using such a feature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With