То, как вы написали код, при компиляции не будет проведена оценка. Когда вы цитируете выражение 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
. Использование квазициклов более естественно, чем ручные вызовы функций сращивания (и вы уже использовали их, безымянный [| ... |]
quoter цитирует выражения 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|]
Отличный ответ! Спасибо. –