Haddock version during build
Claus Reinke
claus.reinke at talk21.com
Thu Jun 19 08:53:28 EDT 2008
>>> Haddock.Interface.Rename
>>> but all I want is basically the equivalent of Traversable's mapM method.
>> Ah, I see the problem, you change the type of a type variable during
>> the traversal - so you have to have some notion of which values are
>> bound to the type variable, and which are not. I'm pretty sure this is
>> impossible with Uniplate, and have no idea about SYB.
>
> If there is a way to do this, it is way too hard to find. I was surprised
> by this limitation, but I now recall it has come up before, with the
> conclusion that gfoldl's type is not quite general enough. It seems
> a common enough problem that it should be fixed, after which SYB
> would again be the default candidate for generic traversal support?
After running my head against the type system for a while,
I've given up (at least, for now;-) and bypassed it. It seems
that the discussion in the SYB paper was somewhat incomplete,
and gfoldl's type is not general enough to express type-changing
maps. Which is really annoying because the derived code for it
is quite capable of handling that, just that I can't find a way to
generalize gfoldl's type to capture that, nor can I find a way to
use the existing gfoldl type to achieve the task.
Another obstacle is #2378, preventing the use of standalone
deriving for Data/Typeable, so I've simply copied a small subset
of HsDoc and written the gfoldl code by hand, to play with a
simplified
renameDoc :: Monad m => HsDoc Name -> m (HsDoc DocName)
As I said, the gfoldl code is general enough to handle the mapping,
only the types get in the way. To demonstrate, I simply coerced
the return types (n2d/d2n), which play no role in the type-based
dispatch. See code below.
The reason that Traversable can handle this is without such
awkwardness is that it hardcodes the recursion - no strategy
combinators - and works only for Functors - handling the map
part. Since SYB seems more general in principle, it would be
nice if Traversable could be defined in terms of Data/Typable,
so that it could share the deriving mechanism. Even better
would be if both could be defined in terms of one derivable
class, without coercions..
Claus
{-# OPTIONS_GHC -fglasgow-exts #-}
import Data.Generics
import Unsafe.Coerce(unsafeCoerce)
data HsDoc id
= DocEmpty
| DocAppend (HsDoc id) (HsDoc id)
| DocString String
| DocParagraph (HsDoc id)
| DocIdentifier [id]
deriving (Eq, Show, Typeable)
gfoldl' :: Typeable id
=> (forall a b . Typeable a => c (a -> b) -> a -> c b)
-> (forall g . g -> c g) -> HsDoc id -> c (HsDoc id)
gfoldl' k z hsDoc = case hsDoc of
DocEmpty -> z DocEmpty
(DocAppend hsDocA hsDocB) -> z DocAppend `k` hsDocA `k` hsDocB
(DocString s) -> z DocString `k` s
(DocParagraph hsDoc) -> z DocParagraph `k` hsDoc
(DocIdentifier ids) -> z DocIdentifier `k` ids
data Name = Name String deriving (Show,Data,Typeable)
data DocName = DocName String deriving (Show,Data,Typeable)
n2d :: Monad m => m (HsDoc Name) -> m (HsDoc DocName)
n2d = unsafeCoerce
d2n :: Monad m => m (HsDoc DocName) -> m (HsDoc Name)
d2n = unsafeCoerce
renameDoc :: Monad m => HsDoc Name -> m (HsDoc DocName)
renameDoc (DocIdentifier ids) =
mapM (\(Name n)->return (DocName n)) ids >>= return . DocIdentifier
renameDoc hsDoc = n2d (gfoldl' k return hsDoc)
where k c x = do c' <- c
x' <- (return `extM` (d2n . renameDoc)) x
return (c' x')
testDoc = DocAppend (DocParagraph (DocAppend (DocIdentifier [Name "well-typed"]) DocEmpty))
(DocAppend (DocString "programs")
(DocIdentifier [Name "don't",Name "go",Name "anywhere"]))
More information about the Cvs-libraries
mailing list