data
type into an
abstract type whose constructors are hidden.
-- The Tree data type ...
data Tree a
= Leaf a |
Node a (Tree a) (Tree a)
-- ... and a function using it
flatten :: Tree a -> [a]
flatten (Leaf x) = [x]
flatten (Node x s t)
= x : flatten s ++ flatten t
|
module Tree (Tree, leaf, node, isLeaf,
isNode, val, left, right) where
data Tree a
= Leaf a |
Node a (Tree a) (Tree a)
isLeaf (Leaf _) = True
isLeaf _ = False
isNode (Node _ _ _) = True
isNode _ = False
val (Leaf x) = x
val (Node x _ _) = x
left (Node _ l _) = l
right (Node _ _ r) = r
leaf = Leaf
node = Node
flatten :: Tree a -> [a]
flatten t
| isleaf t = [val t]
| isNode t
= val t : flatten (left t) ++
flatten (right t)
|
General comment:
Concrete data
types provide direct representations of many kinds of data, and the pattern matching syntax over data
types makes for an intuitive style of programming. The drawback of this is the 'rigidity' which results: the representation of the data is visible to all clients of the type. It is often useful to make the representation abstract, prior to a change or extension of the data type.
Left to right comment:
This is a composite refactoring, built using a series of simpler refactorings, each of which enables the pre-condition of its successor. See cross-references for details. |
Right to left comment:
It is likely that this transformation will only be invoked in circumstances where earlier refactorings have substantially simplified the representation of an ADT. |
Left to right conditions:
There are no conditions on performing this refactoring. |
Right to left conditions:
The concrete representation of an ADT can be made visible simply by exporting the constructors. Conversion to a full pattern-matching form of definition requires definitions to be written in an appropriate form. |
There are no conditions on the conversion of a
data
type into an ADT, and thus no analysis.