неоднозначные последствия - PullRequest
8 голосов
/ 22 марта 2011

Вопрос в том, почему следующий код не работает с выводом типа (ниже показан сеанс REPL для демонстрации) и можно ли это исправить?Более конкретно, чем это отличается от использования CanBuildFrom, который используется компилятором для определения типа возвращаемого значения?

Учитывая этот код:

object S {
    import java.net._

    trait UrlLike[T] {
      def url(s: String): T
    }

    object UrlLike {
      implicit object str extends UrlLike[String]{def url(s: String) = s}
      implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
      implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
    }

    trait UrlSupport {
        val _url: String

        def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
    }
}

У меня есть этот сеанс в REPL (2.8.1):

scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S

scala> import java.net._
import java.net._

scala> import S._
import S._

scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1@155bd22

scala> res0.url : String
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : String
            ^

scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : URL
            ^

scala> res0.url[String]
res3: String = http://example.com

scala> res0.url[URL]
res4: java.net.URL = http://example.com 

Ответы [ 4 ]

5 голосов
/ 22 марта 2011

Я понимаю, почему вы ожидаете, что это сработает, но, очевидно, средство вывода типов не использует возвращаемый тип для вывода T. Я бы тоже этого ожидал.

Что касается неоднозначности, CanBuildFrom позволяет избежать двусмысленности, просто не определяя все на одном и том же "уровне". Например, это решает проблему неоднозначности:

trait LowPriorityImplicits {
  implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
  implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}

object UrlLike extends LowPriorityImplicits {
  implicit object str extends UrlLike[String]{def url(s: String) = s}
}

Однако, не заставит вывод типа работать так, как вы хотите:

scala> res0.url : URL
<console>:16: error: type mismatch;
 found   : String
 required: java.net.URL
       res0.url : URL
            ^

Что указывает на то, что оно, очевидно, делает T логический вывод без учета типа возвращаемого значения.

4 голосов
/ 22 марта 2011
> trait UrlLike[T] {

trait UrlLike[+T] {
2 голосов
/ 22 марта 2011

Это может быть неочевидно из сообщения об ошибке, которое вы видите, но все три следствия, определенные в объекте UrlLike, способствуют двусмысленности (например, попробуйте закомментировать определение uri, и вы увидите двусмысленность сообщается как находящийся между str и url).

Причина неоднозначности заключается в том, что параметр типа T в UrlSupport.url ограничен только требованием, чтобы для него был доступен неявный экземпляр UrlLike. Строка, URL и URI одинаково удовлетворяют этому требованию благодаря экземплярам UrlLike, предоставленным вашими тремя неявными объектами. Компилятор не собирается выбирать один из них для вас произвольно, поэтому он сообщает о неоднозначности.

Если, конечно, вы не разрешите неоднозначность, явно указав аргумент типа, как вы делали в последних двух ваших взаимодействиях REPL.

2 голосов
/ 22 марта 2011

Относительно любой неявной неоднозначности, правило (начиная с Scala2.8) :

При сравнении двух различных применимых альтернатив перегруженного метода или неявного, каждый метод:

  • получает один балл за с большим количеством конкретных аргументов ,
  • и другой балл за , определенный в соответствующем подклассе .

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

Я не думаю, что последствия, связанные с URL или URI, получат другой набор баллов в соответствии с этими критериями.

...