То, как вы написали свой код, во время компиляции оценки не произойдет. Когда вы цитируете выражение 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) |]
Это оценивает хеш-функцию во время компиляции, поскольку внутреннее соединение разрешается после того, как внешнее соединение было разрешено. Кстати, использование fromString
из Data.String
является общим способом построения некоторого OverloadedString
типа данных из String
.
Кроме того, вы должны рассмотреть вопрос о создании квази-квотера для вашего HashString
интерфейса. Использование квазиквотеров более естественно, чем вызов функций сплайсинга вручную (и вы уже использовали их; безымянный [| ... |]
кавычка цитирует выражения Haskell).
Вы бы создали квазиквотер так:
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|]