Recursive types?
Mark Tullsen
tullsen@cs.yale.edu
Tue, 29 May 2001 12:48:52 -0400
Tom Pledger wrote:
> I don't know whether this is a shining example of an advantage,
> and am keen to see other comments.
For what it's worth, I've pulled some snippets from some code I wrote.
I wanted three recursive types which were nearly identical (Exp,ExpQv,ExpPr).
Rather than write three different type declarations
data Exp = ...
data ExpQv = ...
data ExpPr = ...
I was able to abstract out the commonality into one non-recursive type
data FctrExp a = ...
Note how concise some of my "Sample Functions" can be. These would
have been very long and ugly to write were I to use the first
approach. At the expense of now using a "two-level" type, I've gained
some expressiveness.
- Mark
---- Fix Type -----------------------------------------------------------------
data Fix f = In (f (Fix f))
class FixEq f where
fixEq :: Eq a => (f a -> f a -> Bool)
class FixShow f where
fixShowsPrec :: Show a => (Int -> f a -> ShowS)
instance FixEq f => Eq (Fix f) where
(==) (In x) (In y) = fixEq x y
instance FixShow f => Show (Fix f) where
showsPrec p (In x) = showString "In (" . fixShowsPrec p x . showChar ')'
---- Types for Documentation --------------------------------------------------
type Var = String
type Env x = [(Var,x)]
type Pat = Exp
type Type = Exp
---- Form & FormPr Related Types ---------------------------------------------
type Qv = (Exp,Exp)
data Pr = Pstep (ExpPr,Justifier,ExpPr)
| Pletu (Var, Type, ExpPr)
deriving(Show,Eq)
data Justifier = Stub1
deriving (Show,Eq)
---- Exp,ExpPr,ExpQv Types ----------------------------------------------------
data Ftype = Stub2 deriving (Show,Eq)
data Ltype = Stub3 deriving (Show,Eq)
data Const = Stub4 deriving (Show,Eq)
data FctrExp a =
Econ Const
| Evar Var
| Eapp (Ftype, a, a)
| Elet (Ltype, Pat, Type, a, a) -- let x:t=e1 in e2
| Elam (Ftype, Pat, Type, a) -- \x:t=>e
| Eqnt (Ftype, Pat, Type, a) -- |~|x:t=>e
| Etup [a] -- <e1,e2,...>
| Emu a
| Ecase a -- case e
| Ein (a,a) -- In i e
deriving (Show,Eq)
data FctrExpQv a = ExpQvExp (FctrExp a)
| ExpQvQv Qv
deriving (Show,Eq)
data FctrExpPr a = ExpPrExp (FctrExp a)
| ExpPrPr Pr
deriving (Show,Eq)
type Exp = Fix FctrExp
type ExpQv = Fix FctrExpQv
type ExpPr = Fix FctrExpPr
---- Define Appropriate Functors ----------------------------------------------
instance Functor FctrExp where
fmap = fmapFctrExp
fmapFctrExp :: (a->b) -> (FctrExp a -> FctrExp b)
fmapFctrExp f e =
case e of
Econ x -> Econ x
Evar x -> Evar x
Eapp (x,e1,e2) -> Eapp (x,f e1, f e2)
Elet (x,v,t,y,z) -> Elet (x,v,t,f y,f z)
Elam (x,v,t,e) -> Elam (x,v,t,f e)
Eqnt (x,v,t,e) -> Eqnt (x,v,t,f e)
Etup es -> Etup (map f es)
Emu e -> Emu (f e)
Ecase e -> Ecase (f e)
Ein (i,e) -> Ein (f i,f e)
---- Make Exp,ExpQv,ExpPr instances of Show and Eq ----------------------------
instance FixEq FctrExp where fixEq = (==)
instance FixShow FctrExp where fixShowsPrec = showsPrec
instance FixEq FctrExpQv where fixEq = (==)
instance FixShow FctrExpQv where fixShowsPrec = showsPrec
instance FixEq FctrExpPr where fixEq = (==)
instance FixShow FctrExpPr where fixShowsPrec = showsPrec
---- Sample Functions ---------------------------------------------------------
expToExpPr :: Exp -> ExpPr
expToExpPr (In x) = In (ExpPrExp (fmap expToExpPr x))
firstExpPr, finalExpPr :: ExpPr -> Exp
firstExpPr (In x) = case x of
ExpPrExp e -> In $ fmap firstExpPr e
ExpPrPr (Pstep (p,_,_)) -> firstExpPr p
ExpPrPr (Pletu _) -> error "firstExpPr"
finalExpPr (In x) = case x of
ExpPrExp e -> In $ fmap finalExpPr e
ExpPrPr (Pstep (_,_,p)) -> finalExpPr p
ExpPrPr (Pletu _) -> error "finalExpPr"