2012-04-21 11 views
10

Il pacchetto encoding utilizza HaXml nello script di build (in Setup.hs). Capita di usare bit dell'interfaccia che è cambiato tra HaXml-1.19 e HaXml-1.22. Sarebbe bello se il pacchetto di codifica fosse in grado di creare con entrambe le versioni. Ho provato ad utilizzare il solito trucco Cabal, vale a dire, fare qualcosa di similemodifica della modalità di creazione di Setup.hs

{-# LANGUAGE CPP #-} 
#if MIN_VERSION_HaXml(1,22,0) 
-- HaXml-1.22 code 
#else 
-- HaXml-1.19 code 
#endif 

... ma le definisce magiche non possono esistere prima che il pacchetto è configurato, e questo file è in fase di costruzione per rendere possibile la fase di configurazione. Quali sono le mie opzioni? C'è un modo per cambiare il comando che cabal-installa le chiamate per compilare Setup.hs? Esiste un altro meccanismo per la selezione condizionale del codice che elimini la cabala?

+0

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. –

+0

@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). –

+0

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

risposta

4

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)

+0

Sembra fantastico. –

2

Ci non sembrano essere molto numerose manopole in cabal-install/Distribution/Client/SetupWrapper.hs controllare la compilazione di Setup.hs, quindi la soluzione migliore potrebbe essere quella di creare un file di stub Setup.hs che esegue il test di versione e poi giù le mani al Real Setup.hs una volta ha capito qual è la versione.

Un altro trucco consiste nel creare una libreria di shim di compatibilità che usi lo script di installazione, che ha i trucchi della versione appropriata.

Ma forse la vera domanda da porsi è questa: perché Setup.hs utilizza librerie esterne?

+0

Hm, come sarà la risposta? ? Non tenterà ancora di costruire (entrambe) le cose che sto consegnando? –

+0

Giusto, è necessario reinviare GHC con le definizioni di macro appropriate. –

Problemi correlati