2012-02-01 6 views
4

私は、基本的なコレクションを強化するライブラリ関数をいくつか記述しようとしています。それのほとんどはスムーズに行っていますが、私はこの問題を抱えています。スカラー:エラー:パラメータのタイプがありません

class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) { 
    def mapValuesStrict[T, U, R, That](f: U => R)(implicit ev: A <:< (T, U), bf: CanBuildFrom[Repr, (T, R), That]) = { 
    val b = bf(self.asInstanceOf[Repr]) 
    b.sizeHint(self.size) 
    for ((k: T, v: U) <- self) b += k -> f(v) 
    b.result 
    } 
} 
implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]](self: GenTraversableLike[A, Repr]) = new EnhancedGenTraversableLike[A, Repr](self) 

は、ここで私はそれを使用するために行くときに何が起こるかです:

scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict((_:Int).toString) 
res0: List[(Int, java.lang.String)] = List((1,2), (2,3), (3,4), (2,5)) 

scala> List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString) 
<console>:13: error: missing parameter type 
       List((1,2),(2,3),(3,4),(2,5)).mapValuesStrict(x => x.toString) 
                  ^

ので、Scalaはxのタイプを決定することができません。

This answerは、Scalaが別のパラメータを解決するために1つのパラメータを使用しないことを示していますが、別のパラメータリストで問題を解決できることを示しています。しかし、私の場合は、型情報が暗黙的なパラメータにあるので、これはあまり簡単ではありません。

私はメソッドを呼び出すたびにタイプを指定する必要がないので、これを回避する方法はありますか?


更新:オーウェンの助言に基づいて、私はペアのトラバースに特有の豊かなクラスを作成することになった:

class EnrichedPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) { 
    def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = { 
    val b = bf(self.asInstanceOf[Repr]) 
    b.sizeHint(self.size) 
    for ((k: T, v: U) <- self) b += k -> f(v) 
    b.result 
    } 
} 
implicit def enrichPairGenTraversableLike[T, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]) = new EnrichedPairGenTraversableLike(self) 

答えて

6

はい、あります。もっと簡単な例を挙げましょう。私はこれもあなたのより複雑なユースケースの で動作することを願っています。

(new Bar).methWithImplicits(x => x) 

が "不足しているパラメータの型" を与えるため、

たちは

trait Foo[A] 

class Bar { 
    def methWithImplicits[A,B](f: A => B)(implicit foo: Foo[A]) = null 
} 

implicit def fooInt: Foo[Int] = null 

を持っていると言うさて、これは、あなたが記述正確に問題を抱えています。

だから我々がやりたいものを、Scalaは暗黙の最初を見ているように、 明示的に供給機能「の後ろに」暗黙のパラメータを移動することです。まあ、我々はこれを行うことができ 一つの方法は、間接の余分な層を追加することです:

class Bar { 
    def methWithImplicits2[A](implicit foo: Foo[A]) = new { 
     def apply[B](f: A => B) = null 
    } 
} 

(new Bar).methWithImplicits2.apply(x => x) 

構文はとてもきれいではありませんが、これは、動作します。あなたが現在のデザインを見て、あなたが「より早い」段階のいずれかに暗黙のうちに潜入することができるかどうかを見ることです。 あなたの現在のデザインを見てください。たとえば、 mapValuesStrictメソッドは、暗黙的に が指定された後にのみ意味を持ちますので、 ではなくオブジェクトの暗黙のプロパティをメソッドに渡すことがあります。

しかし、それがあなたの設計には便利でない場合は、暗黙的に 変換を使用して逆戻りすることがあります。

implicit def addFoo[A](bar: Bar)(implicit foo: Foo[A]) = new { 
    def methWithImplicits3[B](f: A => B) = null 
} 

しかし残念ながら、私は疑う何があり、それは文句を引き起こして、あまりにも多型である暗黙の値について 検索にそれを原因とスカラ座でのバグです:これは、我々がやりたいものです

could not find implicit value for parameter foo: test.Foo[A] 

これは、暗黙的な変換を使用している場合にのみ発生します。これは、 のバグだと思う理由です。そこで、我々はさらにバックそれを取ることができます:(と、依存方法の種類の-Xexperimental を必要とする):

trait FooWrapper { 
    type AA 
    val foo: Foo[AA] 
} 

implicit def wrapFoo[A](implicit theFoo: Foo[A]) = new FooWrapper { 
    type AA = A 
    val foo = theFoo 
} 

implicit def addFoo(bar: Bar)(implicit foo: FooWrapper) = new { 
    def methWithImplicits3[B](f: foo.AA => B) = null 
} 

そして今

(new Bar).methWithImplicits3(x => x) 
完璧に動作

;)


更新

あなたの特定のケースで

、私はあなたの最善の策は、enhanceGenTraversableに暗黙的に動作するようにだと思います、しかし、残念ながら、同じハックは可能なバグを回避するために必要とされています

// Notice `ev` is now a field of the class 
class EnhancedGenTraversableLike[A, Repr <: GenTraversable[A], T, U] 
    (self: GenTraversableLike[A, Repr], ev: A <:< (T, U)) 
{ 
    def mapValuesStrict[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = { 
     val b = bf(self.asInstanceOf[Repr]) 
     b.sizeHint(self.size) 
     for ((k: T, v: U) <- self) b += k -> f(v) 
     b.result 
    } 
} 

// The Hack 
trait WrappedPairBound[A] { 
    type TT 
    type UU 
    val bound: A <:< (TT, UU) 
} 

implicit def wrapPairBound[A,T,U](implicit ev: A <:< (T,U)) = new WrappedPairBound[A] { 
    type TT = T 
    type UU = U 
    val bound = ev 
} 

// Take the implicit here 
implicit def enhanceGenTraversableLike[A, Repr <: GenTraversable[A]] 
     (self: GenTraversableLike[A, Repr])(implicit ev: WrappedPairBound[A]) = 
    new EnhancedGenTraversableLike[A, Repr, ev.TT, ev.UU](self, ev.bound) 
+0

素晴らしい答えをありがとう!私は物事を2つの "強化された"クラスに分割してしまったので、GenTraversableLike((T、U)、Repr)に固有のクラスを持つことができました。これはあなたが示したように問題を克服し、概念的にも清潔です。 – dhg

関連する問題