La forma en que has escrito el código, ninguna evaluación ocurrirá en tiempo de compilación. Cuando se cita una expresión Haskell con [| ... |]
, se inserta el código/AST citado donde se aplica sin ningún tipo de evaluación, por lo que la escritura:
$(hString "hello, world")
es exactamente lo mismo que escribir:
let s = "hello, world" in HashString (hash $ T.pack s) (T.pack s)
Pero piensa al respecto de esta manera: utiliza [| ... |]
para citar una expresión que se insertará más tarde y genera código en tiempo de compilación con $(...)
. Por lo tanto, si se incluye algún código $(foo)
en una expresión citada bla = [| bar $(foo) |]
, haciendo $(bla)
generará el código bar $(foo)
, que a su vez evaluar foo
en tiempo de compilación. Además, para tomar un valor que genere en tiempo de compilación y generar una expresión a partir de él, utilice la función lift
. Por lo tanto, lo que se quiere hacer es lo siguiente:
import Data.String (fromString)
import Language.Haskell.TH.Syntax
hString s = [| HashString $(lift . hash . T.pack $ s) (fromString s) |]
Esto evalúa la función hash en tiempo de compilación, ya que el empalme interno se resuelve después de que se resolviera el empalme exterior. Por cierto, el uso de fromString
Data.String
es la forma genérica de construir algún tipo de datos de un OverloadedString
String
.
También, usted debe considerar la posibilidad de un cuasi-Quoter para su interfaz de HashString
. El uso de cuasi-quot es más natural que llamar manualmente a las funciones de empalme (y ya las has usado; el anónimo [| ... |]
cita las expresiones de Haskell).
Para ello se crea un quasiquoter así:
import Language.Haskell.TH.Quote
hstr =
QuasiQuoter
{ quoteExp = hString -- Convenient: You already have this function
, quotePat = undefined
, quoteType = undefined
, quoteDec = undefined
}
Esto permitirá escribir HashString
s con esta sintaxis:
{-# LANGUAGE QuasiQuotes #-}
myHashString = [hstr|hello, world|]
Excelente respuesta! Gracias. –