| From: Sebastian Hunt <[EMAIL PROTECTED]>
| Date: Thu, 9 Dec 1993 16:00:13 GMT
| In the interests of keeping things (ie, the haskell type system)
| as simple as possible, I would vote (if I had a vote) against this
| proposal. Unless, of course, I was persuaded that the extension was
| Really Useful. So Simon: what were those programs?
|
| Sebastian
OK, here's my example. I hope it's right. I was writing a compiler
pass which looked at a data type something like
data Expr = Let Bind Expr
| ...
data Bind = MkBind String Expr
Then I had three functions, written in continuation-passing styule, as
follows:
doBinds :: [Bind] -> [Bind]
doBinds (b:bs) = doBindAndScope b (\b' -> b' : doBinds bs)
doExpr :: Expr -> Expr
doExpr (Let b e) = doBindAndScope b (\b' -> Let b' (doExpr e))
doBindAndScope :: Bind -> (Bind -> a) -> a
doBindAndScope (MkBind s e) cont = cont (MkBind s (doExpr e))
The trouble is that the mutual recursion between
doBindsAndScope doExpr
means that doBindsAndScope can't be as polymorphic as its type
signature says it should be. But if it isn't that polymorphic, the
call in doBinds is illegal.
I solved it like this (UTTERLY YUK YUK), by encapsulating the polymorphism
in a fixed data type which simply tags the various expected types at
which the function can be called. Not only is this really quite obscure,
but it also is inefficient at runtime.
data WhatIsIt = ItsABinds [Bind] | ItsAnExpr Expr
doBinds :: [Bind] -> [Bind]
doBinds (b:bs) = case (doBindAndScope b
(\b' -> ItsABinds (b' : doBinds bs))) of
ItsABind bs -> bs
doExpr :: Expr -> Expr
doExpr (Let b e) = case (doBindAndScope b
(\b' -> ItsAnExpr (Let b' (doExpr e))) of
ItsAnExpr e -> e
doBindAndScope :: Bind -> (Bind -> WhatIsIt) -> WhatIsIt
doBindAndScope (MkBind s e) cont = cont (MkBind s (doExpr e))
Simon