[Template-haskell] Using a Typ as a Type
Thu, 4 Sep 2003 09:29:39 +0100
OK, I see a bit better now.
One question you raise (implicitly) is whether you can have splices
y =3D [| 4+5 |]
f x =3D $(h $y)
TH doesn't currently allow this, but there's no difficulty in principle.
To see this, just substitute for y:
f x =3D $(h $[| 4+5 |]) =3D $(h (4+5))
But you also try something that really won't work:
f x =3D $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 =3D 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
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?
| -----Original Message-----
| From: Alastair Reid [mailto:firstname.lastname@example.org]
| Sent: 03 September 2003 16:06
| To: Simon Peyton-Jones; Alastair Reid; email@example.com
| 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
| The following is a simplified version of what I tried to do in
| -- 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 =3D read
| ctype _ =3D "HsInt" -- FFI-defined C type corresponding to Int
| -- instances for freshly defined types
| newtype T =3D T Int
| deriving Show -- included to make the example work
| instance X T where
| f s =3D T (read s)
| g (T x) =3D g x
| generate :: String -> Q Typ -> Q [Dec]
| generate nm typ =3D 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 =3D 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 ++ " =3D " ++ 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 =3D $(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 |] =3D e
| Should this apply to types as well?