2012-02-11 10 views
8

私は単なる文字列とそのハッシュであるシンプルなHashStringクラスを書いていますと、コンパイル時に関数を評価:私のようなもので、コンパイル時にこれらを生成しようとしている今テンプレートHaskellは

data HashString = HashString Int --^hash 
          T.Text --^string! 

$(hString "hello, world") :: HashString 

コンパイル時にハッシュとテキストパッキングが必要です。これはどうすればいいですか?

は、ここで私はこれまで試したものだが、私はその権利があればわからないんだけど、でも私はそれがコンパイル時にすべてを行い確信しています:

hString :: String -> Q Exp 
hString s = [| HashString (hash $ T.pack s) (T.pack s) |] 

答えて

14

あなたのコードを書いている途中、コンパイル時に評価は行われません。あなたは[| ... |]でHaskellの式を引用するとき、あなたはどんな評価せずにそれを適用する場所を引用したコード/ ASTが挿入されているので、書き込み:

$(hString "hello, world") 

は書き込みとまったく同じである:

let s = "hello, world" in HashString (hash $ T.pack s) (T.pack s) 

しかし考えますそれについては、[| ... |]を使用して後で挿入する式を引用し、コンパイル時に$(...)というコードを生成します。したがって、$(foo)というコードを引用符付きの式bla = [| bar $(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) |] 

これは、コンパイル時にハッシュ関数を評価します。ちなみにData.StringfromStringを使用するのはStringOverloadedStringデータ型を構築する一般的な方法です。

また、HashStringインターフェイスの準引用符を作成することを検討する必要があります。準引用符を使用するのは、スプライス関数を手動で呼び出すよりも自然です(既に名前を使用していますが、無名の[| ... |]引用符はHaskell式を引用しています)。

あなたはこのようquasiquoterを作成します。

import Language.Haskell.TH.Quote 

hstr = 
    QuasiQuoter 
    { quoteExp = hString -- Convenient: You already have this function 
    , quotePat = undefined 
    , quoteType = undefined 
    , quoteDec = undefined 
    } 

これは、あなたがこの構文でHashStringの書いてみましょうになります。

{-# LANGUAGE QuasiQuotes #-} 
myHashString = [hstr|hello, world|] 
+0

優秀な答えを!ありがとうございました。 –

関連する問題