Recursive types?
Tom Pledger
Tom.Pledger@peace.com
Tue, 22 May 2001 14:24:55 +1200
David Bakin writes:
| I'm having trouble understanding recursive types (e.g., as described in
| Functional Programming with Overloading and Higher-Order Polymorphism by
| Jones.
|
| He gives as an example
|
|
| > data Mu f = In (f (Mu f))
|
| > data NatF s = Zero | Succ s
| > type Nat = Mu NatF
|
| Among the things I don't get are:
|
| 1. Comparing this to the non-higher-order type:
|
| > data NatX = Zero | Succ NatX
|
| What are the advantages of the higher-order type? What are the
| disadvantages (incl. runtime costs)?
|
| 2. How are values of type Nat represented? (It helps me to think about
| these things concretely.)
_|_
In _|_
In Zero
In (Succ _|_)
In (Succ (In _|_))
In (Succ (In Zero))
In (Succ (In (Succ _|_)))
In (Succ (In (Succ (In _|_))))
In (Succ (In (Succ (In Zero))))
and so on. If you never care about distinguishing In _|_ from _|_,
you can save space and time by declaring `newtype Mu ...' instead of
`data Mu ...', in which case Nat's run-time representation is the same
size as NatX's.
One advantage of such higher-order types is reusability. For example,
this
type CT c k e
= c k (Tree c k e) -- Contained Tree, container, key, element
data Tree c k e
= Empty
| Node (CT c k e) e (CT c k e)
can be used with no frills
newtype Plain k t = Plain t
... :: Tree Plain () e
or with every subtree labelled
... :: Tree (,) String e
or with every subtree inside the ST monad
import ST
... :: Tree STRef s e
etc. I don't know whether this is a shining example of an advantage,
and am keen to see other comments.
Regards,
Tom