9

私は単純なHashStringクラスを書いています。これは単なる文字列とそのハッシュです。

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) |]
4

1 に答える 1

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

これは、外側のスプライスが解決された後に内側のスプライスが解決されるため、コンパイル時にハッシュ関数を評価します。ちなみに、fromStringfromを使用することは、からいくつかのデータ型Data.Stringを構築する一般的な方法です。OverloadedStringString

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

次のような準クォーターを作成します。

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-11T21:26:00.550 に答える