Question

I just start learning Template Haskell, and stuck on simple problem with splicing.
In one module I've implemented function tupleN which replies N-th element of the tuple:

tupleN :: Lift a => a -> Int -> Q Exp
tupleN a n = do
   (TupE as) <- lift a
   return $ as !! n

In the Main module I have:

main :: IO ()
main = do
   let tup = (1::Int,'a',"hello")
   putStrLn $ show $(tupleN $tup 1)

This seems to be working, but it wouldn't. Compiler prints error:

GHC stage restriction: `tup'
  is used in a top-level splice or annotation,
  and must be imported, not defined locally
In the expression: tup
In the first argument of `tupleN', namely `$tup'
In the expression: tupleN ($tup) 1

If I put tuple description right into spliced expression, code become working:

main :: IO ()
main = do
   putStrLn $ show $(tupleN (1::Int,'a',"hello") 1)

What I missing with the first variant?

Était-ce utile?

La solution

You've tried to use tup as a splice, but tup is just an ordinary value. You don't want to prefix it with a $.

Moreover, as the compile error states, since Template Haskell runs during the compilation process, GHC really needs to know what it's doing before it has finished compiling the current module. That means your splice expression can't depend on tup, because that's still being compiled. Inside splices, you can only use literals, imported values, and the special 'name and ''TypeName forms (which you can think of as a sort of literal, I suppose). You can get at some of the information from this compilation by using e.g. reify, but even that can only give you data that's available at compile time – if you want a function you can pass user input, or data constructed from user input, to, that's just impossible.

In short, you can't do exactly what you want to do using Template Haskell. You could, however, define a splice that expands to a function to get the ith element of a tuple of size sz:

import Control.Monad (unless)
import Language.Haskell.TH

tupleN :: Int -> Int -> Q Exp
tupleN sz i = do
  unless (i < sz) . reportError $ "tupleN: index " ++ show i
    ++ " out of bounds for " ++ show sz ++ "-tuple"
  lamE
    [tupP (replicate i wildP
      ++ [varP (mkName "x")]
      ++ replicate (sz - i - 1) wildP)]
    (varE (mkName "x"))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top