10

假设我有一个任意模块

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

其中foobarbaz正确实现等。

我想将此模块具体化为自动生成的数据类型和相应的对象:

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
  }

名称必须与原始模块完全相同。

我可以手动完成,但这非常乏味,所以我想编写一些代码来为我执行此任务。

我不太确定如何处理这样的任务。模板 Haskell 是否提供了检查模块的方法?我应该挂钩一些 GHC api 吗?或者我是否也可以使用更特别的方法,例如刮黑线鳕页面?

4

1 回答 1

3

(这是针对 GHC-7.4.2 的;由于 中的一些更改,它可能无法使用 HEAD 或 7.6 编译Outputable)。我没有找到任何东西来检查 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
于 2012-07-20T12:35:53.310 回答