ライブラリのタイプghciができるだけ直感的に表示できるようにしようとしていますが、より高度なタイプ機能を使用すると多くの問題が発生します。
このコードがファイルにあるとしましょう:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import GHC.TypeLits
data Container (xs::[*]) = Container
Ghciにロードしてから、次のコマンドを入力します。
ghci> :t undefined :: Container '[String,String,String,String,String]
残念ながら、ghciは私にかなり醜い見た目を与えます:
:: Container
((':)
*
String
((':)
* String ((':) * String ((':) * String ((':) * String ('[] *))))))
ghciは、タイプレベルの文字列の砂糖を削除しました。 ghciがこれを実行して、きれいなバージョンだけを提供するのを防ぐ方法はありますか?
関連するメモとして、型レベルのReplicate
関数を作成するとします。
data Nat1 = Zero | Succ Nat1
type family Replicate (n::Nat1) x :: [*]
type instance Replicate Zero x = '[]
type instance Replicate (Succ n) x = x ': (Replicate n x)
type LotsOfStrings = Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String
さて、LotsOfStrings
を使用してタイプをghciに要求すると、次のようになります。
ghci> :t undefined :: Container LotsOfStrings
ghciは素晴らしいです、そして私にかなりの結果を与えます:
undefined :: Container LotsOfStrings
しかし、Replicate
dバージョンを要求すると、
ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)
ghciは、型同義語の代わりに型族を使用しなかった場合、型族の代わりに使用します。
:: Container
((':)
*
[Char]
((':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
なぜghciは型族の代わりをしているのに、型同義語をやっていないのですか? ghciがいつ置換を行うかを制御する方法はありますか?
私が知っている回避策は:kindを使用することです。例えば、
ghci>:kind(Container '[String、String、String、String、String])
与える:
(コンテナ '[String、String、String、String、String]):: *
一方
ghci>:kind! (コンテナ '[String、String、String、String、String])
次のようなものを印刷します:
コンテナ
(( ':)
* [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))
もちろん、公式には、kind
を使用してghciに別の質問をしますが、それは機能します。とにかくundefined ::
を使用することは一種の回避策なので、これで十分かもしれないと思いました。
これは、今後のGHC7.8で修正されます。
データ型がPolyKindsを使用する場合、GHC7.6は種類を出力します。ご覧のように (':) * String ('[] *)
だけでなく(':) String '[]
。
GHC 7.8では、種類はデフォルトで表示されなくなり、データ型は予想どおりリストとしてきれいに出力されます。新しいフラグを使用できます-fprint-explicit-kinds
GHC7.6のように明示的な種類を表示します。この理由はわかりません。おそらく、明示的な種類は、PolyKindsを理解するのに役立つことを目的としていました。
import GHC.TypeLits
data Container (xs::[*]) = Container
Ghciにロードしてから、次のコマンドを入力します。
:t undefined :: Container '[String,String,String,String,String]