hint 使って型推論、 haskell-src-exts を使って Parse

GHC API のラッパー hint を使えばHaskellでも手軽にリフレクションっぽいことができる。例えば動的にHaskellのソースをロードして関数を呼び出す、といったことが数行で書ける。
ところでリフレクション周りで色々やろうとすると、すぐに関数の型を解析したくなるのだけど、hint は 型推論の結果を文字列で返すのでHaskell的には使いにくい。情けない話だが、どうやら GHC APIがそうなっているので仕方ないようだ。Haskellのパーサが必要になる。
haskell-src-exts を使えば、Haskellの型をparse できる。
似たようなことをやる方法に template haskellとか haskell-src という標準のアレがあるけれど、いくつかの拡張構文をサポートしていない。その点 haskell-src-exts はほぼすべての GHC拡張をサポートしている。
というわけで、hint と haskell-src-exts を組み合わせて 型を解析する前段階までを作ってみた。
ちょっとした目的にはややオーバーキルだけど、まあしょうがない。

必要なライブラリ

hint と haskell-src-exts どちらも Hackageにある。

cabal install hint
cabel install haskell-src-exts

使い方

Haskellのモジュールと関数名を指定すると、関数の型を推論して表示してくれる。(ついでに haskell-src-exts でパースした結果も出す。)

Impricit Parameters を使った関数の型も出せる。

$ cat IParamExample.hs 
{-# LANGUAGE ImplicitParams, NoMonomorphismRestriction #-}

module IParamExample where

test = ?a ++ ?b

$ ./Main IParamExample test
Right ("(?b::[a], ?a::[a]) => [a]",TyForall Nothing [IParam (IPDup "b") (TyList (TyVar (Ident "a"))),IParam (IPDup "a") (TyList (TyVar (Ident "a")))] (TyList (TyVar (Ident "a"))))

ソース

続きを読む

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 の使い方はソースに書いた。

続きを読む