RE: [Template-haskell] Using a Typ as a Type
OK, I see a bit better now. One question you raise (implicitly) is whether you can have splices inside splices: y = [| 4+5 |] f x = $(h $y) TH doesn't currently allow this, but there's no difficulty in principle. To see this, just substitute for y: f x = $(h $[| 4+5 |]) = $(h (4+5)) But you also try something that really won't work: f x = $x This is ill staged. TH must *run* the top-level splices. It can't run $x because it doesn't know x's value yet. So in your example, the line let x = f "1" :: $typ is ill-staged because TH can't run $typ, because type is lambda bound. I could just about imagine the following. Suppose your 'generate' was a TH function that *generated a TH function*. So the entire body of 'generate' is quoted. Then I could just about imagine how it might work. The type of generate would look something like | generate :: String -> Q Typ -> Q (Expr (Q [Dec])) (I'm imagining here that Expr is parameterised, which it isn't, but it helps documentation to say (Expr t) means an Expr of type t.) Then a call to generate would look like $($(generate ..)) It would execute by running generate to produce a TH program (essentially inlining only), typechecking that (this is where the overloading you want would be resolved) and then running it. A consequence would be that the TH data types (Expr, Dec etc) would need to get extra constructors to represent quotes, splices etc. Bottom line: today, definitely no. But I hadn't realised before that there could, just, be some benefit to repeated splices like $($(generate...)). I wonder if anyone else has come across this need? Simon | -----Original Message----- | From: Alastair Reid [mailto:alastair@reid-consulting-uk.ltd.uk] | Sent: 03 September 2003 16:06 | To: Simon Peyton-Jones; Alastair Reid; template-haskell@haskell.org | Subject: Re: [Template-haskell] Using a Typ as a Type | | > Perhaps the thing to | > do is to give a simple but concrete example of what you'd like to do. | | The following is a simplified version of what I tried to do in Template | Greencard. | | -- a new class | class X a where | -- member parameterized on result type | f :: String -> a | -- member parameterized by argument type | ctype :: a -> String | | -- instances for old types | instance X Int where | f = read | ctype _ = "HsInt" -- FFI-defined C type corresponding to Int | | -- instances for freshly defined types | newtype T = T Int | deriving Show -- included to make the example work | | instance X T where | f s = T (read s) | g (T x) = g x | | generate :: String -> Q Typ -> Q [Dec] | generate nm typ = do | | -- The next line contains the type splice. | -- Note that it is used to perform a compile-time dictionary | -- lookup not a runtime lookup. | -- I'm not wedded | let x = f "1" :: $typ | | -- Generate C code (should be written to a file, not stdout) | -- Code generated depends on type argument | qIO (putStrLn (ctype x ++ " " ++ nm ++ " = " ++ show x ++ ";\n") | | -- return a variable definition. | -- again, the definition returned depends on the type | -- because it uses 'x' which was produced as a result of | -- the compile-time dictionary lookup. | [d| $nm = $(literal x) |] | | | > Remember, the execution of TH program can be described by ordinary | > rewriting rules (replace the LHS of a function by the RHS of the | > function, suitably instantiated), augmented with the one extra rule | > $[| e |] = e | | Should this apply to types as well? | | -- | Alastair |
participants (1)
-
Simon Peyton-Jones