2013-09-01 9 views
5

Scalaでf束縛多型を達成するために抽象型を使用するべきであることを表現する記事をいくつか読んだ。これは、主に型推論の問題を緩和するだけでなく、再帰型を定義するときに型パラメータが導入すると思われる二次的な増加を取り除くことです。 Scalaで抽象型を持つF束縛多型

これら

はそうのように定義されています

1)ユーザーは、このタイプのオブジェクトを参照しようとするたびに、彼らはまた、参照する必要があります。

trait EventSourced[E] { 
    self => 

    type FBound <: EventSourced[E] { type FBound <: self.FBound } 

    def apply(event: E): FBound 
} 

しかし、これには二つの問題を導入するように見えますFBoundタイプのパラメータ。

def mapToSomething[ES <: EventSourced[E], E](eventSourced: ES#FBound): Something[ES, E] = ... 

2)コンパイラはメッセージで失敗し、上記のような方法のための型パラメータを推測することになりましたができません:

Type mismatch, expected: NotInferredES#FBound, actual: MyImpl#FBound 

はそこに誰も使用しているこれは、コードのにおいのように感じていますコンパイラが型を推論することができるように、その解決法でfの束縛された多型の実装を成功させましたか?

+0

Scalaのコレクションライブラリは問題なく成功したF-囲まれた多型を使用しています。型メンバーではなく型パラメーターを使用します。それに基づいて解決策を試すことができます。 – wingedsubmariner

+0

あなたは私に見せてくれる例、つまり図書館のどの部分でこれをしていますか? –

+0

標準ライブラリの[List](http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List)を参照してください。 GenericTraversableTemplateとLinearSeqOptimizedの継承に使用されているFバウンドの多型に注目してください。 – wingedsubmariner

答えて

3

- というか - あなたが選ぶ必要があります別の設計は、通常あります。それを避ける方法を理解するには、まず私たちはそれを必要とするものを作る知っておく必要があります。タイプは重要なインタフェースはが派生型で導入されるように変更を期待するとき

F-囲まれた多型が発生しました。

これは、変更の期待される領域を構成する代わりに、継承を通じてそれらをサポートしようとするによって回避されます。これは実際にバックGang of Fourのデザインパターンに来る: 'クラスの継承'

オーバー

好意 'オブジェクトの構図' - (四、1995年のギャング)例えば

trait Vehicle[V <: Vehicle[V, W], W] { 
    def replaceWheels(wheels: W): V 
} 

は次のようになります。

trait Vehicle[T, W] { 
    val vehicleType: T 
    def replaceWheels(wheels: W): Vehicle[T, W] 
} 

ここで、「予想される変更」は車種(例:Bike,Car,Lorry)です。前の例では、継承によって追加されると仮定していましたが、Vehicleを使用する関数ではWの推論を不可能にするf境界型が必要でした。コンポジションを使用する新しい方法では、この問題は発生しません。

参照:https://github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism

+0

>コンポジションを使用する新しい方法では、この問題は発生しません。 タイプレベルのチェックを維持したい場合は、最終的に必要になります。例えば、VehicleType [V <:VehicleType> – ayvango

-1

F-bounded polymorphism in Twitter's Scala Schoolの説明を参照してください。

+0

この例では型パラメータを使用しているため、推論の問題が発生します。 def doSomething [ES <:EventSourced [ES、E]、E](that:ES) –

+0

TwitterやScalaライブラリの例では、次のようになります。 F-bound型のパラメータはメソッドではなくクラス自体にあります。 F境界型多型はメソッドが 'this'の型を参照するようにします。正確な型はサブクラスになります。 def map [B、That](f:A => B)(暗黙のbf:CanBuildFrom [Repr、B、That]):それは、 'List'で継承された' TraversableLike'の 'map'の定義を取ります。 '。 ReprはF-Bound型のパラメータでList内のList [A]ですが、TraversableLikeのコードは 'List'を知らなくても書くことができます。 – wingedsubmariner

+0

はい、私は最終的に私のデザインのいくつかを再考する必要があると思います。私が思うには、fバウンド型の多型は、f型のスーパータイプから継承するときに型定義レベルでのみ使用するべきです。しかし、私のコードでは、メソッドレベルで使用されるいくつかのインスタンスがあります...私はこれが変更する必要があると感じています。 –

-1

おそらく、次の実装で何かが不足しています。私は以来、F-有界多型は、ほとんどの場合では避けるべきであることに気づきました

trait EventSourced[E] { 
    self => 

    type FBound <: EventSourced[E] { type FBound <: self.FBound } 

    def apply(event: E): FBound 
} 

trait Something[ES, E] 

def mapToSomething[E](
    eventSourced: ES forSome { 
    type ES <: EventSourced[E] 
    }): Something[eventSourced.type, E] = ??? 

class Test extends EventSourced[Boolean] { 
    type FBound = Test 
    def apply(event:Boolean):FBound = ??? 
} 

val x:Test = ??? 

mapToSomething(x) 
関連する問題