Scala: ошибка: отсутствует тип параметра - PullRequest
4 голосов
/ 01 февраля 2012

Я пытаюсь написать некоторые библиотечные функции для улучшения основных коллекций.Большинство из них прошло гладко, но у меня есть проблема с этим.

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 не использует один параметр для разрешения другого, но отдельные списки параметров могут решить проблему.В моем случае, однако, это не так просто, поскольку информация о типе находится в неявных параметрах.

Есть ли способ обойти это, чтобы мне не приходилось указывать тип при каждом вызове метода?


Обновление: На основе данных Оуэнасовет, я закончил тем, что создал обогащенный класс, специфичный для проходимых пар:

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 голосов
/ 01 февраля 2012

Да, есть. Позвольте мне привести более простой пример. Я надеюсь, что это также будет работать с Ваш более сложный вариант использования.

скажем, у нас есть

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)

дает "пропущенный тип параметра".

Итак, что мы хотели бы сделать, это переместить неявный параметр «за» явно предоставленная функция, так что Scala видит неявное first . Что ж, Один из способов сделать это - добавить дополнительный слой косвенности:

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]

Это происходит только при использовании неявных преобразований, поэтому я думаю, что это ошибка. Таким образом, мы можем взять его на назад еще дальше: (и, требуя -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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...