Проблема с неявными преобразованиями Scala - PullRequest
0 голосов
/ 29 октября 2018

В приведенном ниже фрагменте кода последнее утверждение не компилируется.Однако утверждение непосредственно перед этим фактически компилируется.Это предпоследний оператор - это то, к чему я бы ожидал, что компилятор преобразует последний оператор.Я не понимаю, почему это не работает.Любая помощь приветствуется.

trait ParameterizedBy[A, B] {
    val parameterized: B
  }

object ParameterizedBy {
  implicit def toParameterized[A, B, C](p: ParameterizedBy[A, B])(
    implicit f: B => C): C = f(p.parameterized)
}

trait Wraps[A] {
  val wrapped: A
}

object Wraps {
  implicit def toWrapped[A](w: Wraps[A]): A = w.wrapped
}

val p = new ParameterizedBy[String, Wraps[Int]] {
  override val parameterized: Wraps[Int] = new Wraps[Int] {
    override val wrapped = 6
  }
}

ParameterizedBy.toParameterized(p)(Wraps.toWrapped) + 5

p + 5

1 Ответ

0 голосов
/ 29 октября 2018

Неявное преобразование метода в A => C проблематично, поскольку компилятор не может легко перечислить все возможные классы C, которые имеют ожидаемый метод +, а затем перейти к поиску все возможные методы, которые принимают B и дают C - этот поиск будет длиться вечно.

Я бы предложил избежать неявных аргументов типа B => C для неизвестного типа C. Если вам нужен конвертер, то дайте ему какое-то конкретное имя, например,

trait Unwrap[A, B] extends (A => B)

, который вы затем используете только в этом неявном цепочке.

Грубый набросок того, что вы можете попробовать вместо этого:

import scala.language.implicitConversions

trait ParameterizedBy[A, B] {
    val parameterized: B
  }

object ParameterizedBy {
  implicit def toParameterized[A, B, C](p: ParameterizedBy[A, B])(
    implicit f: Unwrap[B, C]): C = f(p.parameterized)
}

trait Wraps[A] {
  val wrapped: A
}

object Wraps {
  implicit def toWrapped[A](w: Wraps[A]): A = w.wrapped
}

trait Unwrap[A, B] extends (A => B)

object Unwrap {
  implicit def unwrap[A]: Unwrap[Wraps[A], A] = new Unwrap[Wraps[A], A] {
    def apply(w: Wraps[A]): A = w.wrapped
  }
}

val p = new ParameterizedBy[String, Wraps[Int]] {
  override val parameterized: Wraps[Int] = new Wraps[Int] {
    override val wrapped = 6
  }
}

p - 5         // works
(p: Int) + 5  // works with type ascription (to avoid conflicts with `+ String`)
...