Как два связанных конструктора универсальных типов Scala могут ссылаться друг на друга как параметры типа? - PullRequest
4 голосов
/ 07 апреля 2011

В Java 1.6.0_21 первый приведенный ниже пример компилируется нормально, и я думаю, что это потому, что границы типов параметров являются пустыми.То есть в приведенной ниже границе «Z extends Zen» Java позволяет Zen скользить как имя необработанного неуниверсального типа (эквивалентно «стертому» типу во время выполнения).Это может быть неправильно и плохо, но это также может быть полезно, или, по крайней мере, дурацкие хорошие времена в поездке на автобусе домой:

public class CorefTest {

    public static interface Tao<Z extends Zen> {
    }

    public static interface Zen<T extends Tao> {
    }
}

В Scala 2.8.0.final, нижеприведенное компилируется через CleanOceanWithFish, показывая некоторые базовые соединения типа param.Но когда мы получаем, что Zen и Tao являются взаимозависимыми универсальными типами, компилятор Scala отклоняет мою конструкцию ткачества.См. Ошибки компилятора в комментариях.

package heaven.piece
class Lucky {
    trait Water {}
    trait CleanWater extends Water {}
    trait Sea [W <: Water] {}
    trait Fish[S <: Sea[CleanWater]] {}

    trait CleanOceanWithFish[F <: Fish[CleanOceanWithFish[F]]] 
                   extends Sea[CleanWater]{}

// Above code compiles fine, but the type constructor pair below doesn't compile 

    trait Tao[Z <: Zen[Tao[Z]]]{};

    trait Zen[T <: Tao[Zen[T]]]{};
}
// error: type arguments [Lucky.this.Tao[Z]] do not conform to trait Zen's 
//     type parameter bounds [T <: Lucky.this.Tao[Lucky.this.Zen[T]]]

// error: type arguments [Lucky.this.Zen[T]] do not conform to trait Tao's 
//     type parameter bounds [Z <: Lucky.this.Zen[Lucky.this.Tao[Z]]]

Итак, как правильно связать узел Scala (2.8.0) между Дао и Дзен?

Это, конечно, надуманный пример, но яочень хочется использовать Scala для расширения некоторых реальных типов Java, с которыми я работаю в вышеуказанной форме (с которыми пока не помогают экзистенциальные типы через "forSome" и "[_]").Я думаю, что компиляция Zen и Tao в Scala, вероятно, покажет путь к этому расширению Java.Если вы можете рассмотреть вопрос о расширении Java в своем ответе, тем лучше.Спасибо за любую помощь!

Обновление опубликовано после очень полезных первых двух ответов ниже от Никиты С. и Криса Н.

Я эмпирически узнал больше о различных Java +Сценарии привязки Scala.В результате, когда нам нужны совместимые типы coreferent в и Java, и в Scala, тогда эта конструкция Java:

public static interface JavaFunTao<JFZ extends JavaFunZen<? extends JavaFunTao<JFZ>>> {
    public JFZ consider(JFZ someZen, JavaFunTao<JFZ> otherTao);
}
public static interface JavaFunZen<JFT extends JavaFunTao<? extends JavaFunZen<JFT>>> { 
    public JFT meditate(JFT someTao, JavaFunZen<JFT> otherZen);
}

обеспечивает более конкретную типизацию, чем мой первый приведенный выше пример Java (избегаянеобработанных типов) и затем должным образом расширяемым в Scala следующим образом:

class HiFunTao[HFZ <: HiFunZen[  _ <: HiFunTao [HFZ]]] extends JavaFunTao[ HFZ] {
    override def consider(someZen: HFZ, otherTao: JavaFunTao[HFZ]) : HFZ = {
        println (this.toString() + " is considering " + someZen + " and " + otherTao);
        someZen
    }
}
class HiFunZen[HFT <: HiFunTao[ _ <:  HiFunZen [HFT]]] extends JavaFunZen[ HFT] {
    override def meditate(someTao: HFT, otherZen: JavaFunZen[HFT]) : HFT = {
        println (this.toString() + " is meditating on " + someTao + " and " + otherZen);
        someTao
    }
}

Я проверил, что мы можем создавать простые конкретные типы на их основе, создавать их экземпляры и вызывать их методы.Ключевым шагом как в Java, так и в Scala является размещение ограниченного подстановочного знака в точке, где дерево параметров типа возвращается к текущему типу объявления, т. Е. «? Extends» в java и «_ <:» в Scala.</p>

Ответы [ 2 ]

3 голосов
/ 07 апреля 2011

Поскольку ни дзен, ни тао не являются ковариантными, в вашем дзен и дао есть проблема взаимозаменяемости.Это прекрасно для меня под 2.8.1:

trait Tao[+Z <: Zen[Tao[Z]]]

trait Zen[+T <: Tao[Zen[T]]]

Конечно, если вы хотите медитировать на Z или T, то это также не будет работать для вас, по крайней мере, не так, как указано из-запроблема наличия параметра ковариантного типа в контравариантной позиции.Вы можете обойти эту проблему следующим образом:

trait Tao[+Z <: Zen[Tao[Z]]] {
  def meditate[M >: Z](m: M) = ()
}

trait Zen[+T <: Tao[Zen[T]]] {
  def meditate[M >: T](m: M) = ()
}

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

Обновление:

Это также, кстати, позволяет избежать проблемы, упомянутой в обновлении ответа Н.С.Кворцова.Это хорошо компилируется:

class Zazen extends Zen[Tao[Zazen]]
2 голосов
/ 07 апреля 2011

Я думаю, это то, что вам нужно:

class MyClass {

  trait Tao[Z <: Zen[_]]{};
  trait Zen[T <: Tao[_]]{};

}

Этот фрагмент успешно скомпилирован в Scala 2.8.1

Обновление

К сожалениюрасширение CorefTest.Zen и CorefTest.Tao в скале невозможно.Вот почему.

Единственный способ реализовать интерфейсы в java - это использовать raw types :

public class TaoImpl<Z extends CorefTest.Zen> implements CorefTest.Tao<Z> { }

public class ZenImpl<T extends CorefTest.Tao> implements CorefTest.Zen<T> { }

, чем можно создать экземпляры классоввот так:

TaoImpl<ZenImpl> tao = new TaoImpl<ZenImpl>();
ZenImpl<TaoImpl> zen = new ZenImpl<TaoImpl>();

Но scala не поддерживает необработанные типы .Так что TaoImpl и ZenImpl просто не могут быть определены.Пожалуйста, посмотрите эту ветку электронной почты и вопросы # 2091 и # 1737 для подробного обсуждения

...