2016-03-09 5 views
38

閲覧型崩れコードは、私が出会ったこの一見無関係の{}herehereは `T {}` Scalaでやるん何

trait Witness extends Serializable { 
    type T 
    val value: T {} 
} 

trait SingletonOps { 
    import record._ 
    type T 
    def narrow: T {} = witness.value 
} 

それは何もしませんが、どうやらそれがないので、私はほとんどタイプミスとしてそれを無視何か。このコミットを参照してください:https://github.com/milessabin/shapeless/commit/56a3de48094e691d56a937ccf461d808de391961

私はそれが何をするか分かりません。誰か説明できますか?

+1

何を「広げる」んコミットメッセージに意味: 'どうやら空の微細化は意味「me'.'を広げませんか? –

+0

拡張は暗黙的な型の拡大を指しています(例えば、List1(2.0)はList [Double]なので、int1は2.0に一致するように2倍に拡大できるためです)。この主旨は説明するのに役立つかもしれません:https://gist.github.com/milessabin/65fa0d4ef373781d3ab4 –

+0

Widenは、シングルトンタイプを推測するのを避けたいので、シングルトンタイプの 'X.type'から' object X'のタイプを広げることを意味します。ここではシングルトンタイプが望ましい。 –

答えて

51

任意の種類のタイプと抽象非型部材定義の{}囲まれたシーケンスが続くことができます。これは「洗練」として知られており、洗練されている基本タイプに対して追加の精度を提供するために使用されます。実際には洗練された型の抽象型メンバに制約を表現するために洗練が最も一般的に使用されます。

このシーケンスは空であることが許されており、シェイプレスソースコードで見ることができる形式で、T {}はタイプがTで、空のリファインメントです。空のリファインメントは空です...したがって、追加の制約は洗練されたタイプに追加されないため、タイプTT {}は同等です。

scala> implicitly[Int =:= Int {}] 
res0: =:=[Int,Int] = <function1> 

なぜ私はシェイプレスでこのような明らかに無意味なことをするのでしょうか?それは洗練の存在と型推論の間の相互作用のためです。 Scala言語仕様のthe relevant sectionを見ると、タイプ推論アルゴリズムは少なくともいくつかの状況でシングルトンタイプを推測しないようにしようとします。あなたがf2の定義から見ることができるようにここで

scala> class Foo ; val foo = new Foo 
defined class Foo 
foo: Foo = [email protected] 

scala> val f1 = foo 
f1: Foo = [email protected] 

scala> val f2: foo.type = foo 
f2: foo.type = [email protected] 

、ちょうどそれを行うことの一例であるScalaのコンパイラは、値fooは、より正確なタイプfoo.type(すなわち。val fooのシングルトン型)を持っていることを知っていますただし、明示的に要求されない限り、より正確な型を推測することはありません。代わりに、f1の場合のように非シングルトン(すなわち、拡大)タイプFooを推論します。

しかし、型崩れでWitnessの場合、私は明示的にWitnessの全体のポイントは、シングルトンタイプ経由型と値のレベルの間を通過するために私たちを有効にある)シングルトン型はvalueメンバーの用途のために推論することがをしたいです、そうするためにScalaコンパイラに説得できる方法はありますか?

それはあなたがs2が割り当てられているのに対し、最初のケースs1に広がっタイプStringとして型付けされた、上記のREPL転写産物で見ることができるように空の微細化はまさにその、

scala> def narrow[T <: AnyRef](t: T): t.type = t 
narrow: [T <: AnyRef](t: T)t.type 

scala> val s1 = narrow("foo") // Widened 
s1: String = foo 

scala> def narrow[T <: AnyRef](t: T): t.type {} = t // Note empty refinement 
narrow: [T <: AnyRef](t: T)t.type 

scala> val s2 = narrow("foo") // Not widened 
s2: String("foo") = foo 

ないことが判明シングルトンタイプString("foo")

これはSLSによって義務付けられていますか?いいえ、でもそれはそれと一致していて、何らかの意味があります。 Scalaの型推論機構の多くは、spec'edではなく実装定義されており、これはおそらくそれの最も驚くべき問題の1つです。

+0

最初に、同等の型は同じように動作し、実際には同じ表現を持つ必要があります。これは驚くべきことであり、邪悪なことである。しかし、私はその動作に混乱しています。私は拡大を "foo" .type {} 'に適用して広げることができないと推測しています。マクロ注釈 'T @ narrow'の後ろに' T {} 'を隠すことができますか? – Blaisorblade

+0

はい、そうです。マクロ注釈が既存の構文を使用するよりも優れていると考えている理由はありませんが、使用されていない構文があります。 –

+0

大きな説明ありがとう@MilesSabin – pathikrit

関連する問題