Hatena::Grouphaskell

[ pred x | x <- "Ibtlfmm!ojllj" ] RSSフィード

2008-03-07

$(tGen ''SomeState) → data SomeStateT m a = ... 23:20

StateTをnewtypeでラップする手順を長々と日本語で書いた(id:illillli:20080228#p1)が、TemplateHaskellでプログラムにしたほうが早いことに気づいた。

まだStateでラップする部分しか書いていない。ここまででいくつかTemplateHaskellの問題に気づいた。

  • [t| .. |](型の準クォート)や[d| .. |](宣言の準クォート)の中では展開が使えない

このため、全体的に宣言を生成するのが面倒だった。

例えばこう書けるはずのところを

[d| newtype $fooT m a = $conFooT
    { $runT :: StateT $foo m a
    } deriving (Functor, Monad, MonadIO, MonadTrans)
  |]

こう書かねばならなかった。

  let tvars = map mkName ["m", "a"]
      [m, a] = map varT tvars
  newtypeD
    (cxt [])
    fooT
    tvars
    (recC conFooT $
      [varStrictType runT $
        strictType notStrict $
          apps [conT ''StateT, foo, m, a]])
    [''Functor, ''Monad, ''MonadIO, ''MonadTrans]

検索して出てきた話では、[d|は括弧の中で複数の宣言ができるので、スコープの問題が出てくるそうだ。Q [Dec]じゃなくてQ Dec用の括弧を作ればいいと思うのだが、議論をそれ以上読んでいない。[t|の方は修正があるらしい。

  • GHCのderivingの拡張に対応していない

newtype節やdata節の構築子の型はこうなっている

data Dec
  = ...
  | DataD Cxt Name [Name] [Con] [Name]
  | NewtypeD Cxt Name [Name] Con [Name]

それぞれ最後の[Name]がderiving節に当たる。これはつまりTemplateHaskellではderiving節にMonadState SomeStateと書けないということだ。

> runQ [d| newtype A m a = A (StateT Int m a) deriving (Monad, MonadState Int) |]
<interactive>:1:5:
    Non-H98 deriving clause not (yet) handled by Template Haskell
      MonadState Int

仕方なくインスタンス化の宣言を別に書くようにしている。MonadReaderも同じことをしないといけないので少し意気消沈気味。

トラックバック - http://haskell.g.hatena.ne.jp/illillli/20080307