Haskell98可変長引数ハックにみる,各処理系のcontext reductionの違い

Olegさんの Generic polyvariadic printf in Haskell98 は、プレーンなHaskell98で可変長引数関数をつくり,printfを実現しています. 関数の型(a->r)は型構築子(->)と型引数a rからなる型 (->) a r なわけで,型クラスのインスタンスでうまいこと回せば、こんなこともできるんですねーというお話. すごい.
(OlegさんによるHaskellの型安全なprintfについては、ここにちょっと追記)

このprintfは Haskell98 なので codepad の Hugsでも動きます. ここに貼りました:
http://codepad.org/xY2quxH0#comment-C6lfIn51

context reduction の違いを見てみる

ところでこいつは,HugsGHCの各バージョンにおける context reduction の違いを見るのにちょうど良さげな例になってるみたいですので、みてみましょう. (昨日の ToPS の後の飲み会でも似たような話を振ったので,ちょうど復習になったのですが,あと新しい発見が!)

hugsやghciで,次のように,いくつかの引数を可変長引数関数に適用した後の型を表示させてみます:

hugs-or-ghci> printf "%s%s%s" True True True

Hugs (March 2005)

hugs> :t printf "%s%s%s" True True True
printf "%s%s%s" True True True :: SPrintF a => a

期待通り. あとは unR :: RString -> String を使って 型変数 a を RString にしてやれば インスタンス SPrintF RString の方が選択されて=> がなくなります.もちろん引数を追加してもOK (フォーマットは%s%s%sなので表示されないけど).目出度い.

GHC (6.6)

ghci-6.6> :t printf "%s%s%s" True True True
printf "%s%s%s" True True True :: (SPrintF (Bool -> Bool -> Bool -> t)) => t

コイツ全然やる気ないですね. SPrintF (a->r) なので インスタンスHugsのように簡約されてもよさそうなもんですが,やってくれません.

GHC (6.8, 6.10)

ghci-6.10> :t printf "%s%s%s" True True True
printf "%s%s%s" True True True :: (SPrintF (Bool -> t)) => t

!?

要約

Hugs が一番 eager(?) に文脈を簡約しています. GHC6.6は lazy(?) ですね.
しかしおどろくべきことに,我らがHaskell型レの星GHC 6.8と6.10 はなんだか中途半端に SPrintF (Bool -> t) を SPrintf t へ簡約できずにいます.


なぜなんでしょう。。。 GHC 6.8のchangelogを読んでもこのへんの変更はよくわからない.よく見ると associated typesが入ったのが GHC6.8か.うーむ.
いつもの-fglasgow-exts (つまり-XMultiParamTypeClasses -XFunctionalDependencies -XFlexibleInstances -XFlexibleContextsとか) あと -XUndecidableInstances や -XNoMonomorphismRestriction とかを加えてみたのですが,変わりませんでした.(実のところghci の :t で型を見るときは単相性制限はないので -XNoMonomorphismRestrictionは冗長)
haskell-cafeに投げればわかりそうだけど