Reputation: 833
In the following code:
data Point = Point { x :: Int,
leftHeight :: Int,
rightHeight :: Int}
data Rectangle = Rec Point Point
rec1 = Rec p1 p2
There are several constraints when creating Rec
such as:
x p1 < x p2
(leftHeight p1 ) should always be zero
(rightHeight p2 ) should always be zero
rightHeight p1 == leftHeight p2
Is there a way to enforce these constraints at type level?
Because I'm using QuickCheck
to generate some sample Rec
but these contraints make QuickCheck
very slow to generate random samples.
edit: I've solved the slow QuickCheck issue. But anyway still curious if such constraint can be expressed in Haskell
Upvotes: 1
Views: 89
Reputation: 50864
To point out the obvious, the standard way of enforcing these constraints at type level would be to define your Rectangle
differently:
data Rectangle = Rec
{ x1 :: Int
, x2 :: Int
, height :: Int
}
This enforces all constraints except "x1 < x2". You can use smart destructors to recreate the rectangle's Point
"fields":
point1 :: Rectangle -> Point
point1 (Rec x1 _ h) = Point x1 0 h
point2 :: Rectangle -> Point
point2 (Rec _ x2 h) = Point x2 h 0
and define a smart constructor (which can also enforce the "x1 < x2" constraint):
rect :: Point -> Point -> Rectangle
rect (Point x1 0 h1) (Point x2 h2 0) | h1 == h2 && x1 < x2 = Rec x1 x2 h1
rect _ _ = error "bad rectangle"
Seriously, this really is the best way to enforce constraints at the type level in Haskell!
Upvotes: 3