Template Haskell, information about data constructor types

Hi I'm trying to write a function: reaches :: Type -> Q [Type] The intention is that reaches (Either Bool [Int]) would return [Either Bool [Int], Bool, [Int], Int] - i.e. all types which are contained by the initial type at any level. I took a shot at this: getTypes :: Type -> Q [Type] getTypes t = do let (ConT c, cs) = typeApp t TyConI dat <- reify c return $ concatMap ctorTypes $ dataCtors dat reaches :: Type -> Q [Type] reaches t = f [] [t] where f done [] = return done f done (t:odo) | t `elem` done = f done odo | otherwise = do ts <- getTypes t f (t:done) (odo ++ ts) Where typeApp splits a type to find its constructor, ctorTypes gets the types of the fields, and dataCtors gets the constructors in a data type. Unfortunately reify doesn't seem to work on types. Is it possible to do what I am after? Thanks Neil

| Where typeApp splits a type to find its constructor, ctorTypes gets | the types of the fields, and dataCtors gets the constructors in a data | type. Unfortunately reify doesn't seem to work on types. Is it | possible to do what I am after? reify takes a Name, not a Type. Perhaps you mean that reify doesn't work on type constructors? (E.g. reify ''Maybe). It should -- if you think it doesn't can you concoct a test case and submit it? Simon

Hi Simon,
On 6/4/07, Simon Peyton-Jones
| Where typeApp splits a type to find its constructor, ctorTypes gets | the types of the fields, and dataCtors gets the constructors in a data | type. Unfortunately reify doesn't seem to work on types. Is it | possible to do what I am after?
reify takes a Name, not a Type.
I am passing it a name, since I pattern match on the ConT: let (ConT c, cs) = typeApp t TyConI dat <- reify c typeApp follows the AppT's to get a vector apply, so ConT is at the very left of a chain on AppT.
Perhaps you mean that reify doesn't work on type constructors? (E.g. reify ''Maybe). It should -- if you think it doesn't can you concoct a test case and submit it?
I'm not sure if I'm doing something wrong, as I haven't managed to get it working for any type constructors. A test case: ghci -fth Prelude> :m Language.Haskell.TH Language.Haskell.TH> $( reify (mkName "Maybe") >>= error . show ) Results in: <interactive>:1:3: `Maybe' is not in scope at a reify In the expression: $[splice]((reify (mkName "Maybe")) >>= (error . show)) In the definition of `it': it = $[splice]((reify (mkName "Maybe")) >>= (error . show)) <interactive>:1:3: Exception when trying to run compile-time code: user error (IOEnv failure) Code: let >>= = (>>=) Q $dMonad $dMonad = Language.Haskell.TH.Syntax.$f20 show = show Info $dShow $dShow = Language.Haskell.TH.Syntax.$f60 in (>>=) [Info, Exp] (reify (mkName "Maybe")) ((.) [[Char], Q Exp, Info] (error (Q Exp)) show) In the expression: $[splice]((reify (mkName "Maybe")) >>= (error . show)) In the definition of `it': it = $[splice]((reify (mkName "Maybe")) >>= (error . show)) The initial error is that Maybe is not in scope at reify. Changing to "Data.Maybe.Maybe" doesn't help, trying "String" doesn't work, creating a module and declaring a type in there then putting that fragment in the file doesn't work. Thanks Neil

On Mon, Jun 04, 2007 at 10:45:30AM +0100, Neil Mitchell wrote:
On 6/4/07, Simon Peyton-Jones
wrote: Perhaps you mean that reify doesn't work on type constructors? (E.g. reify ''Maybe). It should -- if you think it doesn't can you concoct a test case and submit it?
I'm not sure if I'm doing something wrong, as I haven't managed to get it working for any type constructors. A test case:
ghci -fth Prelude> :m Language.Haskell.TH Language.Haskell.TH> $( reify (mkName "Maybe") >>= error . show )
This works: $( reify ''Maybe >>= runIO . print >> [| 'c' |] ) (modulo printing the result 4 times due to http://hackage.haskell.org/trac/ghc/ticket/1201) I don't think your example is expected to work. Thanks Ian

Sorry to be slow. Instead of
| Language.Haskell.TH> $( reify (mkName "Maybe") >>= error . show )
say
| Language.Haskell.TH> $( reify ''Maybe >>= error . show )
Which works fine. The notation ''Maybe means "the type constructor Maybe that's in scope".
When you use mkName, TH builds a Language.Haskell.TH.Name which just contains the string "Maybe", and reify interprets that as a data constructor. This is really a design flaw. Perhaps a Name should contain a name-space. That would be useful here (the NameSpace would say "I'm a tycoon"). But it's *not* useful when (say) lambda-binding a local variable. Or maybe reify should take a NameSpace argument.
Anyway that's the problem and a solution is to hand. But if you have a good idea for a better design, please yell. And do please update the Wiki with whatever you have learned!
Simon
| -----Original Message-----
| From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-
| bounces@haskell.org] On Behalf Of Neil Mitchell
| Sent: 04 June 2007 10:46
| To: Simon Peyton-Jones
| Cc: Haskell Café
| Subject: Re: [Haskell-cafe] Template Haskell, information about data
| constructor types
|
| Hi Simon,
|
| On 6/4/07, Simon Peyton-Jones
participants (3)
-
Ian Lynagh
-
Neil Mitchell
-
Simon Peyton-Jones