data
type, which may be recursive, is transformed into an existential type, resembling a traditional object-oriented data representation. This transformation founders with binary functions over the data
type.
data Shape
= Circle Float |
Rect Float Float
area :: Shape -> Float
area (Circle f) = pi*r^2
area (Rect h w) = h*w
perim :: Shape -> Float
perim (Circle f) = 2*pi*r
perim (Rect h w) = 2*(h+w)
|
data Shape
= forall a. Sh a => Shape a
class Sh a where
area :: a -> Float
perim :: a -> Float
data Circle = Circle Float
instance Sh Circle
area (Circle f) = pi*r^2
perim (Circle f) = 2*pi*r
data Rect = Rect Float Float
instance Sh Rect
area (Rect h w) = h*w
perim (Rect h w) = 2*(h+w)
|
General comment:
It is possible to see this refactoring first being used left to right, to allow the addition of constructors in a localised way, and then from right to left, to permit the introduction of binary functions over the data type.
Left to right comment:
The code on the LHS collects the constructors of the type in a single place, namely the definition of On the other hand, in the RHS code, the changes required for a new constructor are localised to one place, namely the |
Right to left comment:
The RHS gives an object-oriented formulation of the data type, but is limited in not being able to represent binary operations over the If a new function is to be added to the code, then each |
Left to right conditions:
The functions over the data type (here the type |
Right to left conditions:
The form of the existential type must be as if it had arisen by the left to right transformation. |