2013-01-08 61 views
2

我剛開始學習模板Haskell,並堅持與拼接簡單的問題。
在一個模塊我實現功能tupleN其回覆元組的第N個元素:
問題與模板Haskell舞臺限制

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) 

我與第一個變體丟失了怎麼辦?

+0

模板哈斯克爾工作在編譯時,不是運行。拼接必須能夠在編譯時運行。 –

+0

@LouisWasserman我知道這條規則:)我只想把'tup'變量捕獲到拼接表達式中。關於'tup'類型的信息在編譯時可用,所以可以在這裏捕獲它,我想。 –

回答

5

您試圖使用tup作爲拼接,但tup只是一個普通的值。您不想以$爲前綴。

此外,由於編譯錯誤指出,由於模板Haskell在編譯過程中運行,GHC在編譯當前模塊之前確實需要知道它正在做什麼。這意味着您的拼接表達式不能依賴於tup,因爲它仍在編譯中。在拼接內部,您只能使用文字,導入的值以及特殊的'name''TypeName表單(我認爲您可以將其視爲一種文字)。您可以通過使用例如編輯器來獲得該彙編中的一些信息。 reify,但即使這樣也只能爲您提供在編譯時可用的數據 - 如果您希望某個功能可以將用戶輸入或從用戶輸入構建的數據傳遞給該功能,那根本不可能。

總之,你不能做到你想要使用模板哈斯克爾。你可以,不過,定義擴展爲一個函數來獲取大小sz的元組的i元素的拼接:

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"))