hint から Template Haskell を使って reify

下の記事の続き。
hintは意外に私の欲しい機能がなく、たとえば「あるレコード型のフィールド名をすべて取得」みたいなことができない。Template Haskell の reify 関数なら、任意の識別子について reify が使えるののに…
というわけで、 ややアクロバティックだけど、Template Haskellでreifyしたデータを、 hintのinterpret関数でこちら側にもってくる、というコードを書いた。
必要なライブラリはhintのみ。

使い方

まず、下で説明する Meta.hs をカレントに置く。
下の Foo.hs から

module Foo where
data Point = Point {x::Int, y::Int}

Point型の情報を取り出して、そのままprintする.

$ ./Main Foo Point
Right (TyConI (DataD [] Foo.Point [] [RecC Foo.Point [(Foo.x,NotStrict,ConT GHC.Types.Int),(Foo.y,NotStrict,ConT GHC.Types.Int)]] []))

ソース

レイフィケーションのために Meta.hs というのを準備した。以前このブログにアップした気がするのだけど見つからないので再掲。
Meta.hs の使い方はソースに書いた。

少し修正して、毎回Reify.hsを生成しないようになった。spliceのことをすっかりわすれていた…

module Main where

import Control.Monad.Trans (liftIO)
import Data.List

-- from hint
import qualified Language.Haskell.Interpreter as H
import Language.Haskell.Interpreter.Unsafe

-- template haskell
import Language.Haskell.TH as TH

import System.Environment

-- 他の環境で動かす時はここを変える
confs = ["/opt/local/lib/ghc-6.10.4/package.conf", "/Users/keigoi/.ghc/i386-darwin-6.10.4/package.conf"]

main = do
  [mod,typname] <- getArgs
  fieldsTest mod typname

fieldsTest mod typname = do
  res <- H.runInterpreter $ fields mod typname
  print res

fields mod typname = do
    myLoadModule ["Meta", mod]
    H.interpret ("$( meta ''"++typname++")") (H.as :: TH.Info)

myLoadModule :: [String] -> H.Interpreter ()
myLoadModule mods = do
  H.reset
  unsafeSetGhcOption ("-i"++concat (intersperse ":" confs))
  H.set [H.languageExtensions H.:= [H.ImplicitParams, H.TemplateHaskell]]
  H.set [H.installedModulesInScope H.:= True]
  H.loadModules $ map (++".hs") mods
  H.setTopLevelModules mods
  H.setImportsQ [("Prelude", Nothing)]