2013-05-22 8 views
9

で失敗し、我々は(Scalaで)次のクラスといくつかの値を持っていると言う:地図はスカラ&型崩れにおけるジェネリック型のサブタイプ

class A[T](val x: T) 
class B[T](x: T, val y: T) extends A[T](x) 

val x1 = new A("test") 
val x2 = new B(1,2) 
val x3 = new B("foo","bar") 
val x4 = new A(1) 

さらに、我々は(型崩れを使用して)以下のポリモーフィック関数の値を定義します:すべてが成功

f(x1); f(x2); f(x3); f(x4) 

を(とすべき私見):

object f extends (A ~> Option) { 
    def apply[T](s: A[T]) = Some(s.x) 
} 

は、今、私たちは呼び出すことができます。しかし:これが機能することを

Some("test") :: Some(1) :: Some("foo") :: Some(1) :: HNil 

注:私は期待していた

val list = x1 :: x2 :: x3 :: x4 :: HNil 
list.map(f) 

// could not find implicit value for parameter mapper: 
// shapeless.Mapper[f.type,shapeless.::[A[String],shapeless.::[ 
// B[Int],shapeless.::[B[String],shapeless.::[A[Int],shapeless.HNil]]]]] 

val list2 = x1 :: x4 :: HNil // only instances of A 
list2.map(f) 

UPDATE

それはそう、我々は個別のケースを指定した場合、うまいです:

object f extends Poly1 { 
    implicit def caseA[T] = at[A[T]]{s => Some(s.x)} 
    implicit def caseB[T] = at[B[T]]{s => Some(s.x)} 
} 

しかし、少し賢くこれを表現しようとすると、(いなくても、単純なアプリケーションのために)動作しません。

object f extends Poly1 { 
    implicit def caseA[T, S <: A[T]] = at[S]{s => Some(s.x)} 
} 
+2

私は現時点では完全な答えを出すことはできませんが、最も簡単な修正点は、最後のバージョンの 'f'(すなわち' S <%A [T] ')で' S ' 。少なくとも、それはうまくいくはずであり、 'A'のすべてのサブタイプに対してケースを追加する必要はありません。 –

+0

@TravisBrown迅速な回答をいただきありがとうございます。それは本当にうまくいくようです。私は本当にあなたが単純な答えやポインタを持っている場合、なぜ知りたいのですか?さもなければ - >コード掘り – gzm0

答えて

9

あなたの最良の選択肢がバインドビューを使用するには、@ TravisBrownの提案の一つ、

です
object f extends Poly1 { 
    implicit def caseA[T, S <% A[T]] = at[S]{s => Some(s.x)} 
} 

又は、多かれ少なかれ同等、型制約、

object f2 extends Poly1 { 
    implicit def caseA[S, T](implicit ev : S <:< A[T]) = at[S]{s => Some(s.x)} 
} 

や共通性を要因あなたの2ケースソリューションのバリエーション、

object f3 extends Poly1 { 
    def asub[T](s: A[T]) = Some(s.x) 
    implicit def caseA[T] = at[A[T]](asub) 
    implicit def caseB[T] = at[B[T]](asub) 
} 

それは型崩れの多形性関数の値が直接あなたのように初期定義を動作させるために必要な引数の型の分散の種類をサポートするように変更される可能性は低いですこれは、型固有のケースを非常に正確に区別する能力(非常に望ましいIMO)と矛盾するためです。

関連する問題