ghciがタイプリストとタイプファミリーを廃止するのはなぜですか?これを選択的に無効にできますか?


93

私のライブラリで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

今、私が使用するタイプをghciに尋ねるとLotsOfStrings

ghci> :t undefined :: Container LotsOfStrings

ghciは素晴らしく、かなりの結果が得られます。

undefined :: Container LotsOfStrings

しかし、Replicatedバージョンを要求すると、

ghci> :t undefined :: Container (Replicate (Succ (Succ (Succ (Succ (Succ Zero))))) String)

型の同義語の代わりにghciが型ファミリーを置き換えます:

:: Container
       ((':)
          *
          [Char]
          ((':)
             * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

ghciが型の同義語ではなく型ファミリーの代わりをしているのはなぜですか?ghciが置換を行うタイミングを制御する方法はありますか?


7
型シノニムは純粋に人間が使用するように設計されているためです。型シノニムをそのように記述/参照したいために型シノニムを作成したことを認めるため、置換は行われません。タイプファミリーはタイプを表示するのではなく、実際にタイプを計算/推定するためのものなので、タイプファミリーで置き換えられます。
AndrewC 2013年

あなたの問題の解決策はあなたの質問にあります-省略したい場合は型の同義語を作成してください。
AndrewC 2013年

2
@AndrewC私はあなたのコメントに関連する別の質問を考えました:なぜ文字列のタイプが時々表示され[Char]、時々表示されるのStringですか?
Mike Izbicki、2013年

1
私は考えてそれが元で見つかった型シノニムを維持するGHCiの試みを。つまり、関数がの型として宣言されている場合、String->Stringその結果の型はとして表示されStringます。ただし、たとえば"abc"(と同じ'a':'b':'c':[])のように、ピースから型を構築する必要がある場合、保持する同義語はありません。これは純粋な推測です。
n。「代名詞」m。

4
@nm:より一般的な推論型が、より一般的ではない明示的に名前が付けられた型変数と統合する場合、GHCは型変数の名前を保持するために同様の試みを行うことに注意してください。明示的なタイプであればStringが型変数f aor [a]で統一されて[Char]同様の理由で後で表示されるとます。
CAマッキャン2013年

回答:


2

私が知っている回避策は:kindを使用することです。例えば、

ghci>:kind(コンテナ '[文字列、文字列、文字列、文字列、文字列])

与える:

(コンテナ '[文字列、文字列、文字列、文字列、文字列]):: *

ながら

ghci>:kind!(コンテナ '[文字列、文字列、文字列、文字列、文字列])

このようなものを印刷します:

コンテナ

(( ':)

  *
  [Char]
  ((':)
     * [Char] ((':) * [Char] ((':) * [Char] ((':) * [Char] ('[] *))))))

もちろん、公式にでghciに別の質問をしkindていますが、これは機能します。undefined ::とにかく使うのが回避策なので、これで十分かもしれないと思いました。


私はundefined ::簡単な例を示すためだけに使用していました。本当の問題は、1000種類の異なるタイプのリストのタイプを持つエラーメッセージを受け取ったときです。印刷するのにページが必要で、解析が非常に困難です。
Mike Izbicki 2013

ええ、十分公正です。気づいたかもしれない。より良い答えをあなたに借りています
user2141650

2

これは、今後のGHC 7.8で修正されています。

GHC 7.6は、データ型がPolyKindsを使用する場合、種類を出力します。だからあなた(':) * String ('[] *)はただの代わりに見る(':) String '[]

GHC 7.8では、デフォルトでは種類は表示されなくなり、予想どおり、データ型はリストとしてかなり出力されます。新しいフラグ-fprint-explicit-kindsを使用して、GHC 7.6のように明示的な種類を表示できます。この理由はわかりませんが、おそらく明示的な種類がPolyKindsの理解を助けるためのものでした。


0
import GHC.TypeLits

data Container (xs::[*]) = Container

それをghciにロードしてから、次のコマンドを入力します。

:t undefined :: Container '[String,String,String,String,String]

そう...?あなたはまだ、私が推測する、すなわちString ((':) * String ((':) * String ((':) * ...
leftaroundabout
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.