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