Подтвердить что ты не робот

Scala просмотр приложения puzzler

Скажем, у нас есть две следующие черты:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

И неявное преобразование из второго в первое:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

Мы создаем Bar и список целых чисел:

val bar = new Bar {}
val stuff = List(1, 2, 3)

Теперь я ожидаю, что следующее будет работать:

bar howMany stuff

Но это не так:

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff
                          ^

Итак, переходим к спецификацию, которая имеет это сказать (выделение жирным шрифтом принадлежит мне):

Представления применяются в трех ситуациях.

  • [Здесь не актуально.]

  • В выборе e.m с e типа T, , если селектор m не обозначает член T. В этом случае выполняется поиск вида v применим к e и результат которого содержит член с именем m. поиск продолжается, как в случае неявных параметров, где неявная область охвата - таковая из T. Если такое представление найдено, выбор e.m преобразуется в v (e).m.

  • В выборе em (args) с e типа T, , если селектор m обозначает некоторый член T, но ни один из этих членов не применим к аргументам args, В этом случае выполняется поиск вида v которая применима к e и результат которой содержит метод m который применим к args. Поиск продолжается, как в случае неявные параметры, где неявная область - таковая из T. Если такой взгляд найден, выбор e.m преобразуется в v (е).m(арг).

Итак, мы пытаемся сделать следующее, думая, что это должно быть слишком абсурдно работать:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar { def howMany = throw new Exception("I don't do anything!") }

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

Но он (как на 2.9.2, так и на 2.10.0-RC2, по крайней мере):

scala> bar howMany stuff
res0: Int = 3

Это приводит к некоторому действительно странному поведению, например, в этом обходном пути для этой проблемы.

У меня есть три (тесно связанных) вопроса:

  • Есть ли простой способ (т.е. тот, который не включает добавление поддельных методов с соответствующим именем), чтобы правильно применить представление в исходном случае выше?
  • Может ли кто-нибудь предоставить чтение спецификации, которая учитывает это поведение?
  • Предполагая, что это предполагаемое поведение, вообще ли оно имеет смысл?

Я также ценю любые ссылки на предыдущие обсуждения этой проблемы - мне не очень повезло с Google.

4b9b3361

Ответ 1

Для всех ссылок это может быть только ошибкой. Как вы знаете, это сообщение об ошибке:

<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]

Список [A] не является реальным типом - он применяется к его собственному параметру типа. Это не тип, который может потребоваться, поскольку он не является типом, который может быть выражен.

[Править - это слишком рано, кто знает, о чем я говорю. Игнорируйте приведенное выше, но вы все равно можете следовать ссылке.]

Соответствующий билет для этого https://issues.scala-lang.org/browse/SI-6472.

Ответ 2

Это похоже на ошибку, поэтому мои ответы:

  • найдите ошибку simliar, сообщенную против компилятора Scala, и если не найдена, сообщите о новой ошибке https://issues.scala-lang.org/
  • эта часть спецификации, похоже, не имеет значения в этом случае, поскольку она не говорит о типе вывода
  • не имеет для меня никакого смысла

PS. В 2.8.1 ваш способ добавления метода фиктивного метода в Bar не делает его компиляцией.

Ответ 3

Замените Foo следующим образом:

trait Foo[_] { def howMany(xs: List[_]) = xs.size }

Это работает, что также делает для меня гораздо больше смысла, потому что вы абсолютно не заинтересованы в A.

Ответ 4

Ваше неявное преобразование, похоже, делает именно то, что вы ему сказали.

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

Преобразует панель в новый объект Foo[A]. Поэтому, в свою очередь,

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff

Он ищет тип "A".

Чтобы сделать эту работу так, как вы хотите ее для себя (я думаю), вместо определения представления по признаку вы можете сделать это в функции.

trait Foo { def howMany[A](xs: List[A]) = xs.size }
trait Bar
implicit def bar2foo[A](bar: Bar) = new Foo{}
val bar = new Bar {}
val stuff = List(1, 2, 3)

тогда он должен дать вам результат, который вы хотите.

scala> bar howMany stuff
res0: Int = 3

или вы можете определить представление о неявной функции

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

implicit def bar2foo[A](bar: Bar) = new Foo[Int] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

Лично я считаю, что определение его в функции более чистое.

Ответ 5

Это, несмотря на уродливость, работает:

(bar: Foo[Int]) howMany stuff