L'interfaccia Data.Data
è in grado (quasi!) Di costruire e decostruire i valori di un tipo che può o non può esistere. Sfortunatamente, HaXml non sembra avere istanze Data
per i suoi tipi, e non puoi definirne uno dato che non puoi riferirti al tipo che potrebbe o non potrebbe esistere, quindi dobbiamo ricorrere a Template Haskell:
I seguenti esportazioni modulo qnameCompat
:
{-# LANGUAGE TemplateHaskell #-}
module HaXmlCompat (qnameCompat) where
import Language.Haskell.TH
qnameCompat :: Q [Dec]
qnameCompat = do
mi <- maybeReify "N"
case mi of
Nothing -> sequence [
tySynD (mkName "QName") [] [t| String |],
valD [p| toQName |] (normalB [| id |]) [],
valD [p| fromQName |] (normalB [| Just |]) []]
Just (DataConI n _ _ _) -> do
s <- newName "s"
sequence [
valD [p| toQName |] (normalB (conE n)) [],
funD (mkName "fromQName") [
clause [conP n [varP s]] (normalB (appE [| Just |] (varE s))) [],
clause [ [p| _ |] ] (normalB [| Nothing |]) []]]
Just i -> fail $
"N exists, but isn't the sort of thing I expected: " ++ show i
maybeReify :: String -> Q (Maybe Info)
maybeReify = recover (return Nothing) . fmap Just . reify . mkName
Quando impiombato al livello più alto usando Template Haskell, qnameCompat
controllerà se N
esiste. Se lo fa, produce il seguente codice:
toQName = N
fromQName (N s) = Just s
fromQName _ = Nothing
In caso contrario, si produce il seguente:
type QName = String
toQName = id
fromQName = Just
Ora è possibile creare e decostruire Element
s, per esempio utilizzando l'estensione ViewPatterns:
myElt :: String -> Element i
myElt = Elem (toQName "elemName") [] []
eltName :: Element i -> String
eltName (Elem (fromQName -> Just n) _ _) = n
ViewPatterns è conveniente, ma non essenziale, naturalmente: con normale pattern matching sul risultato di fromQName
funzionerà altrettanto bene.
(Queste idee sono ciò che mi ha portato a sviluppare la notcpp package, che comprende maybeReify
e di alcuni altri programmi di utilità utili)
Come gravi sono i cambiamenti di interfaccia? Che tipo di cambiamenti sono? È possibile che template haskell possa essere in grado di salvarti, a seconda di cosa sono. –
@benmachine L'unico vero cambiamento è che il costruttore 'Element' ora assume un valore di tipo' data QName = N String | SomethingIDon'tCareAbout' invece di un 'String'. Il file 'Setup.hs' usa il costruttore' Element' sia come una funzione (sempre con un 'String' letterale) sia per la corrispondenza dei pattern (a volte con un' String' letterale e talvolta con un pattern variabile catch-all). –
Quindi sarebbe sufficiente se tu avessi le funzioni 'toQName' e' fromQName' tali che quando esista 'QName',' toQName = N' e 'fromQName' gira' N s' in 'Just s' (e qualcos'altro in' Nothing '), mentre quando' QName' non esiste, 'toQName = id' e' fromQName = Just'? Allora potresti essere in grado di fare ciò che vuoi con i modelli di visualizzazione? Penso che 'toQName' e' fromQName' possano essere definiti con template haskell, usando idee simili a quelle presenti nel mio [pacchetto notcpp] (http://hackage.haskell.org/package/notcpp) –