制限

2015-11-17 15 views
7

Haskellの中箱なしタイプは、これらの制限を持っている理由、私は疑問に思う:制限

newtype Vec = Vec (# Float#, Float# #) 

いますが、型synonimを定義することができます:あなたはアンボクシングタイプのためのnewtypeを定義することはできません

  1. type Vec = (# Float#, Float# #) 
    
  2. タイプファミリーはボックス化されていないタイプを返すことができません:

    type family Unbox (a :: *) :: # where 
        Unbox Int = Int# 
        Unbox Word = Word# 
        Unbox Float = Float# 
        Unbox Double = Double# 
        Unbox Char = Char# 
    

この背後にあるいくつかの根本的な理由があります、またはそれは誰もがこの機能を求めていないという理由だけでは?

答えて

7

Haskellのパラメトリック多形は、t :: *型のすべての値がランタイムオブジェクトへのポインタとして一様に表現されているという事実に依存しています。したがって、同じマシンコードが多態性値のすべてのインスタンス化に対して機能します。

RustまたはC++の対照多型関数。例えば、そこにあるアイデンティティ関数は、forall a. a -> aに類似した型を持ちますが、異なるa型の値が異なる可能性があるため、コンパイラは各instatiationに対して異なるコードを生成する必要があります。

data Id = Id (forall a. a -> a) 

を、このような機能は、任意のサイズのオブジェクトのために正しく動作しなければならないので、これはまた、我々は、ランタイム・ボックスの周りに多型の関数を渡すことができないことを意味します。例えば、ランタイムforall a. a -> a関数が、a値のサイズとコンストラクタ/デストラクタに関する情報を保持する暗黙の引数を必要とする場合など、この機能を使用するには追加のインフラストラクチャが必要です。

さて、newtype Vec = Vec (# Float#, Float# #)の問題は、たとえVecは、いくつかのt :: *の値は、それを扱うことができない見込ん種類*、ランタイムコードを持っていることです。 Haskellオブジェクトへのポインタではなく、スタックで割り当てられたfloatのペアであり、Haskellオブジェクトを期待するコードに渡すと、segfaultまたはエラーが発生します。

一般に(# a, b #)はポインタサイズである必要はないため、ポインタサイズのデータ​​フィールドにはコピーできません。

#タイプを返すタイプファミリーは、関連する理由で許可されていません。次のことを考えてみましょう:

type family Foo (a :: *) :: # where 
    Foo Int = Int# 
    Foo a = (# Int#, Int# #) 

data Box = forall (a :: *). Box (Foo a) 

当社BoxFoo aが異なるa -sため、異なるサイズを有しているので、表現のランタイムではありません。一般に、#を超える多型は、Rustのように異なるインスタンシエーションに対して異なるコードを生成する必要がありますが、これは通常のパラメトリック多型と悪影響を及ぼし、多態性値の実行時表現を難しくするのでGHCはこれを気にしません。

ああ、それは私の第三質問してきたはずです

+1

"です。なぜそれは種類 '*'を持たなければならないのですか? 'Vec =(#Float#、Float##) 'と書くと、Vecはkindが'# 'なので、newtypeには'# 'もあると思います。 –

+1

'type Vec = ... 'は単なる同義語です。 'newtype'は、ラップされた値の型とは異なる新しい型を定義します。新しい型を定義するためのすべてのHaskellの構造体がkind *で返るように起こります。 unboxed型の 'newtype'-sは、異なるサイズのオブジェクトのポリモーフィズムを可能にするために前述したインフラストラクチャの大きなチャンクを必要とします。そうでなければ、単調にしか使用できず、ラップされた型。 –

+0

@AndrásKovácsこれは、種類「#」で作成できましたが、その後、 'id :: a - > a'は' a ::〜 'のために' a〜Vec'に特化することはできません。この制限は、未処理のボックス化されていないデータを渡すときにランタイムがボックス化されたデータを一様に(ポインタ付きで)処理することに関連するため、ボックス化されていない各タイプに対してカスタムの 'id'が必要です。 'int 'は参照型ではないので、Javaが' T 'のようなジェネリックを持つことができない点とあまり違いはありません。 – chi

4

newtype一方がアンボックス化タプルのために定義することができないクラスインスタンス

instance C Vec where ... 

を定義することを可能にします。タイプ同義語はそのような機能性を提供しない。

また、Vecはボックス型ではありません。つまり、種別変数が許可されていない限り、一般的にVecの型変数をインスタンス化することはできません。たとえば、[Vec]は許可しないでください。コンパイラは、「通常の」newtypesと「unboxed」newtypesを何らかの形で追跡する必要があります。これは、データ・コンストラクタVecがコンパイル時にunboxed値をラップできる(実行時に削除されるため)という唯一の利点です。これはおそらく、型推論エンジンに必要な変更を加えることを正当化するのには十分ではないでしょう。

+1

(使用可能な実装は、おそらく考案することができなかったことをけれども言っていない): 'クラスC(:なぜあなたは、このような箱なしタイプの上にクラスを定義することはできませんu ::#)where ... '? –

+0

"Vecはボックスタイプではありません"なぜそれはそのようにしなければならないのですか?タイプsynonim 'type Vec =(#Float#、Float##)'のような '' '' newtype'はどうしてですか? –

+0

"コンパイラは、"通常の "newtypesと" unboxed "newtypesを何らかの方法で追跡する必要があります。定期的な種類のチェックでは不十分ですか? –