Scala:错误:缺少参数类型

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 的类型。

这个答案 表明 Scala 不使用一个参数来解决另一个参数,但是可以通过分离的参数列表解决问题。然而,在我的情况下,由于类型信息包含在隐式参数中,这并不容易。

有没有办法绕过这个问题,使我不必每次调用方法时都指定类型?


更新:根据Owen的建议,我最终创建了一个专门用于可遍历对的增强类。

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)
1个回答

6

是的,有这个功能。让我给你举一个更简单的例子,希望它也能适用于你更为复杂的应用场景。

假设我们有以下内容:

trait Foo[A]

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

implicit def fooInt: Foo[Int] = null

现在这个问题正如你所描述的那样,因为
(new Bar).methWithImplicits(x => x)

出现"missing parameter type"错误。

我们希望的是将隐式参数“放在”显式提供的函数之后,这样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
}

但不幸的是,我怀疑Scala存在一个错误,导致它搜索的隐式值过于多态化,从而引起了投诉:

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

这种情况只会在使用隐式转换时发生,这也是我认为它是一个bug的原因。因此,我们可以更深入地探讨它:(并且需要对依赖方法类型进行-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中,尽管可惜,同样需要使用相同的hack来解决可能存在的错误:

// 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)

感谢您提供的出色答案!我最终将事物分成了两个“增强”类,以便我可以有一个专门针对GenTraversableLike[(T, U), Repr]。正如您所展示的那样,这克服了问题,并且在概念上也非常清晰。 - dhg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接