你寫代碼的方式,編譯時不會進行評估。當你引用一個Haskell表達[| ... |]
,所報碼/ AST插入您應用它沒有任何評價,所以寫:
$(hString "hello, world")
是完全一樣的文字:
let s = "hello, world" in HashString (hash $ T.pack s) (T.pack s)
但認爲它是這樣的:你用[| ... |]
引用稍後插入的表達式,你產生在編譯時有$(...)
代碼。所以,如果你包括在引述表達bla = [| bar $(foo) |]
一些代碼$(foo)
,做$(bla)
將生成的代碼bar $(foo)
,這反過來將在編譯時評估foo
。此外,拍攝您在編譯時產生的值,並且從它的表達,可以使用lift
功能。所以,你想要做什麼是這樣的:
import Data.String (fromString)
import Language.Haskell.TH.Syntax
hString s = [| HashString $(lift . hash . T.pack $ s) (fromString s) |]
這種評估在編譯時哈希函數,因爲外部拼接得到解決後,內部拼接解決。順便說一句,使用fromString
從Data.String
是從String
構建一些OverloadedString
數據類型的通用方法。
此外,你應該考慮做一個準報價者爲您HashString
接口。採用準quoters比手動調用拼接功能更自然(你已經使用過;無名[| ... |]
加引號引用哈斯克爾表達式)。
您可以創建這樣一個quasiquoter:
import Language.Haskell.TH.Quote
hstr =
QuasiQuoter
{ quoteExp = hString -- Convenient: You already have this function
, quotePat = undefined
, quoteType = undefined
, quoteDec = undefined
}
這將讓你寫HashString
s與這句法:
{-# LANGUAGE QuasiQuotes #-}
myHashString = [hstr|hello, world|]
出色答卷!謝謝。 – 2012-02-11 21:31:52