3

Template Haskell の学習を始めたばかりで、スプライシングに関する単純な問題に固執しています。あるモジュールでは、タプルの N 番目の要素を返す
関数を実装しました。tupleN

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

メインモジュールには次のものがあります。

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

これは機能しているように見えますが、そうではありません。コンパイラはエラーを出力します:

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

タプルの説明を結合された式に入れると、コードが機能するようになります。

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

最初のバリアントで欠けているものは何ですか?

4

1 に答える 1

5

tupスプライスとして使用しようとしましたtupが、通常の値です。プレフィックスを付けたくありません$

さらに、コンパイルエラーが示すように、Template Haskell はコンパイルプロセス中に実行されるため、GHC は現在のモジュールのコンパイルを完了する前に、自分が何をしているのかを知る必要があります。つまり、あなたの splice 式は に依存することはできません。それはtupまだコンパイル中だからです。splices 内では、リテラル、インポートされた値、および特殊なフォーム'name''TypeNameフォーム (一種のリテラルと見なすことができると思います) のみを使用できます。eg を使用して、このコンパイルからいくつかの情報を取得できますがreify、それでもコンパイル時に利用可能なデータしか提供できません。関数が必要な場合は、ユーザー入力、またはユーザー入力から構築されたデータを渡すことができます。不可能です。

要するに、Template Haskell を使用してやりたいことを正確に行うことはできません。ただし、関数に展開してsize のタプルのithsz要素を取得するスプライスを定義することはできます。

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"))
于 2013-01-08T22:55:57.430 に答える