web-dev-qa-db-ja.com

GHCタプルがサイズ62に制限されているのはなぜですか?

Haskell 98レポート から:

タプルのサイズに上限はありませんが、Haskellの実装によっては、タプルのサイズを制限し、より大きなタプルに関連付けられたインスタンスを制限する場合があります。ただし、すべてのHaskell実装は、Eq、Ord、Bounded、Read、およびShowのインスタンスとともに、サイズ15までのタプルをサポートする必要があります。 (...)

ただし、GHCが62を超えるサイズのタプルをサポートしないことはよく知られています。GHCiでサイズ63のタプルを作成しようとすると、次のようになります。

<interactive>:1:1: error:
    A 63-Tuple is too large for GHC
      (max size is 62)
      Workaround: use nested tuples or define a data type

これはHaskell98の仕様に準拠しており、62を超えるサイズのタプルは非常に不要である可能性が高いことを認識していますが、GHCの場合とまったく同じである理由はわかりません。


要約すると:

  • タプルのサイズ制限があるのはなぜですか?
  • サイズ制限が特に62になっているのはなぜですか?

加えて:

  • これがGHC6.12.2以降のみに当てはまるのはなぜですか?
  • 他の著名なHaskell実装はこれを行いますか?彼らの理由は何ですか?
21
AJFarmar

コメントのこの変更のタイミングは間違っていると思います。まず、私が知る限り、6.12.1より前の[〜#〜] long [〜#〜]以降、制限が存在していました。 2002年11月のTrac#98 に見られるように、バージョン5.02.2では、制限は(62ではなく)37であり、より大きなタプルを使用しようとすると、不思議なメッセージが生成されました。

_Switches_tupel.lhs:1:
Failed to find interface decl for
`PrelTup.(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)'
    from module `PrelTup'
_

Simon Peyton-Jonesは、コンパイルパイプラインの早い段階でコンパイラにサイズをチェックさせ、より適切なエラーメッセージを生成させることでバグを修正しました(Git commit b44c6881 に表示されます)。このコミットが行われるまでに、制限はすでに37から62に引き上げられていたため(テンプレートHaskellの作業をHEADに統合したGit commit 9af77fa4)、GHC5.04が62タプルの制限とより適切なエラーメッセージとともにリリースされました。

元のTrac#98のバグは、制限の理由を示していると思います。 _ghc/compiler/prelude/TysWiredIn.hs_では、タプル型とデータコンストラクターのセットが事前に割り当てられています。

_boxedTupleArr, unboxedTupleArr :: Array Int (TyCon,DataCon)
boxedTupleArr   = listArray (0,mAX_Tuple_SIZE) [mk_Tuple Boxed   i 
                    | i <- [0..mAX_Tuple_SIZE]]
unboxedTupleArr = listArray (0,mAX_Tuple_SIZE) [mk_Tuple Unboxed i 
                    | i <- [0..mAX_Tuple_SIZE]]
_

ここで、_mAX_Tuple_SIZE_は問題の62タプル制限です。ただし、これらの事前に割り当てられた配列を実際に使用する関数は、オンデマンドでより大きなコンストラクターを生成できます(「特別にビルドする」)。

_tupleTyCon :: Boxity -> Arity -> TyCon
tupleTyCon sort i | i > mAX_Tuple_SIZE 
                = fst (mk_Tuple sort i)  -- Build one specially
tupleTyCon Boxed   i = fst (boxedTupleArr   ! i)
tupleTyCon Unboxed i = fst (unboxedTupleArr ! i)
_

これは、Simonが5.04のエラーメッセージを追加する前にコンパイラが行っていたことです。特別にビルドされたものです。

残念ながら、これにより、コンパイルプロセスの後半で、コンパイラが_ghc/libraries/ghc-prim/GHC/Tuple.hs_で指定されたリストで大きすぎるタプルのインターフェイス定義を見つけることができなかったときにエラー(セグメンテーション違反ではなく、単なるエラー)が発生しました。 _TysWiredIn.hs_の見出し_The Tuple types_の下にある_Tuple.hs_の(少し古くなった)コメントによると、_.../GHC/Tuple.hs_の宣言は、タプルコンストラクターの情報テーブルとエントリコードを構築するために使用されます。任意の大きなタプルに対して、プログラムでその場で生成されます。

では、これは現代のGHCにとって何を意味するのでしょうか。さて、上記と同じ技術的な理由で、コンパイラは任意の大きなタプルを生成する準備ができていますが、_a = (False,...,False) -- imagine 100 Falses main = let (x,_,...,_) = a in print x _で一致する宣言が必要であるという事実によって課せられる制限があります。

タプル長チェックを無効にしてソースからGHCをコンパイルし、いくつかの実験を実行しました。結果のコンパイラは、100タプルで次のプログラムを正常にコンパイルして実行しました。

_a = (False,...,False)  -- imagine 100 Falses
main = let (_,...,_,x) = a
       in print x
_

そしてそれは「False」を印刷しました。同じタプルの最後の要素を取得するように変更すると、正常に機能しました。

_a = (False,...,False)  -- imagine 100 Falses
main = let (x,_,...,_,y) = a
       in print (x,y)
_

ただし、プログラム:

_[1 of 1] Compiling Main             ( Tuple.hs, Tuple.o )
Linking Tuple ...
Tuple.o(.data+0x0): error: undefined reference to 'ghczmprim_GHCziTuple_Z100T_con_info'
collect2: error: ld returned 1 exit status
`gcc' failed in phase `Linker'. (Exit code: 1)
_

リンケージエラーで失敗しました:

_Tuple.hs_

最初の2つのプログラムでは、コンパイラーが欠落しているコンストラクターへの参照を最適化したと思いますが、最後のプログラムではそれが必要でした。 _Tuple.hs_に100タプルの宣言を追加し、コンパイラーを再構築した後、3つのプログラムすべてがコンパイルされ、正常に実行されました。

要するに、手動で作成されたタプルのリストを_Tuple.hs_でコンパイルすると、サイズ62までのタプルをサポートするために必要なデータ構造が生成され、このデータ構造の生成を__()から独立して再実装する十分な動機がありません。 SOMECODE)__クラッチ。もしそうなら、GHCはおそらく任意のサイズのタプルをサポートするでしょう。

余談ですが、マヌエルのセグメンテーション違反に関する_Tuple.hs_のメモ(この質問へのコメントの1つで参照)は、2001年7月に_libraries/base/Data/Tuple.hs_にチェックインされたときのものであるため、 GHC6.12.1とは何の関係もありません。この問題は、おそらく最大値がSimonによって62に設定された理由ですが、この制限は現在のGHCには適用されていないようです。

34
K. A. Buhr