2012-07-20 7 views
10

Supongamos que tengo un módulo arbitrariaReify un módulo en un registro

module Foo where 
foo :: Moo -> Goo 
bar :: Car -> Far 
baz :: Can -> Haz 

donde foo, bar y baz se implementan correctamente, etc.

me gustaría materializar este módulo en una forma automática -generado tipo de datos y objeto correspondiente:

import Foo (Moo, Goo, Car, Far, Can, Haz) 
import qualified Foo 

data FooModule = Foo 
    { foo :: Moo -> Goo 
    , bar :: Car -> Far 
    , baz :: Can -> Haz 
    } 

_Foo_ = Foo 
    { foo = Foo.foo 
    , bar = Foo.bar 
    , baz = Foo.baz 
    } 

Los nombres deben ser exactamente los mismos que en el módulo original.

Pude hacerlo a mano, pero eso es muy tedioso, así que me gustaría escribir algún código para realizar esta tarea por mí.

No estoy seguro de cómo abordar una tarea así. ¿Proporciona Template Haskell una forma de inspeccionar los módulos? ¿Debo conectarme a alguna api de GHC? ¿O estoy tan bien con un enfoque más ad hoc como raspar páginas de eglefino?

+3

¿Podría usar 'haskell-src-exts' para analizar el origen del módulo, luego crear su tipo de datos y generar un nuevo archivo fuente? –

+0

haskell-src-exts es una gran idea, pero analizar la fuente no sería necesariamente suficiente. Por ejemplo, la fuente de [Data.Map] (http://hackage.haskell.org/packages/archive/containers/0.5.0.0/doc/html/src/Data-Map.html) simplemente reexporta datos. Map.Lazy con algunas cosas extra. Necesito el cierre transitivo de todas las exportaciones que un módulo dado realmente exporta. También sería bueno poder extraer los datos del módulo sin tener que inspeccionar la fuente. –

Respuesta

3

(Esto es para GHC-7.4.2; probablemente no se compilará con HEAD o 7.6 debido a algunos cambios en Outputable). No encontré nada para inspeccionar los módulos en TH.

{-# LANGUAGE NoMonomorphismRestriction #-} 
{-# OPTIONS -Wall #-} 
import GHC 
import GHC.Paths -- ghc-paths package 
import Outputable 
import GhcMonad 

main :: IO() 
main = runGhc (Just libdir) $ goModule "Data.Map" 

goModule :: GhcMonad m => String -> m() 
goModule modStr = do 
    df <- getSessionDynFlags 
    _ <- setSessionDynFlags df 
    --^Don't know if this is the correct way, but it works for this purpose 

    setContext [IIDecl (simpleImportDecl (mkModuleName modStr))] 
    infos <- mapM getInfo =<< getNamesInScope 
    let ids = onlyIDs infos 
    liftIO . putStrLn . showSDoc . render $ ids 

onlyIDs :: [Maybe (TyThing, Fixity, [Instance])] -> [Id] 
onlyIDs infos = [ i | Just (AnId i, _, _) <- infos ] 

render :: [Id] -> SDoc 
render ids = mkFields ids $$ text "------------" $$ mkInits ids 

mkFields :: [Id] -> SDoc 
mkFields = vcat . map (\i -> 
    text "," <+> pprUnqual i <+> text "::" <+> ppr (idType i)) 

mkInits :: [Id] -> SDoc 
mkInits = vcat . map (\i -> 
    text "," <+> pprUnqual i <+> text "=" <+> ppr i) 


-- * Helpers 

withUnqual :: SDoc -> SDoc 
withUnqual = withPprStyle (mkUserStyle neverQualify AllTheWay) 

pprUnqual :: Outputable a => a -> SDoc 
pprUnqual = withUnqual . ppr 
Cuestiones relacionadas