2016-11-01 4 views
3

Ниже не компилируется из последней строки:Косвенно завернутые черты с элементом типа не компилирует

object ImplicitWrappedTraitWithType { 

    trait Wrapper[+T] { 
    def unwrap: T 
    } 

    object Wrapper { 
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w 
    } 

    trait IO[In] { 
    type Out 

    def out: Out 
    } 

    implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] { 
    override def unwrap: IO[In] {type Out = String} = new IO[In] { 
     override type Out = String 
     override val out: Out = "yeah" 
    } 
    } 

    val wrap = Wrapper[IO[String]] 
    val io: IO[String] = wrap.unwrap 
    val out: String = io.out //actual type: unwrap.Out 
} 

Что я могу сделать, чтобы убедить компилятор, что val out является String?


Предварительное редактирование - игнорировать этот

Пример 1 - это не компилируется:

object ImplicitWrappedTraitWithType { 
    class Wrapper[T] 
    object Wrapper { 
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w 
    } 
    trait IO[In] { 
    type Out 
    } 
    implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = null 

//client code 
    Wrapper[IO[String]] 
} 

Пример 2 - тогда как это делает:

object ImplicitWrappedTraitWithType { 
    class Wrapper[T] 
    object Wrapper { 
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w 
    } 
    trait IO[In] { 
    type Out 
    } 
    implicit def decoder[In]: Wrapper[IO[In]] = null 

//client code 
    Wrapper[IO[String]] 
} 

В коде клиента я не знаю, какой будет тип Out, но мне нужно иметь к нему доступ, когда я извлекаю экземпляр IO из Wrapper (код для этого не показан).

Как изменить «Пример 1» для компиляции, сохраняя параметр «Выход» таким образом, который отображается для кода клиента.

(Прокомментируйте, если эта формулировка не ясна)

+1

* В коде клиента я не знаю, какой будет тип Out, но мне нужно иметь к нему доступ, когда я извлекаю экземпляр IO из Wrapper * Но он будет виден вам через 'IO [Т] .Out'. Я не уверен, что понимаю проблему. –

+1

@ YuvalItzchakov во втором примере 'Out' не имеет ограничений. –

+1

@ Jasper-M Я вижу, что он безусловный, но я не уверен, что OP хочет, чтобы это было так, как он говорит о «видимости». Я пытаюсь понять, что он имеет в виду. –

ответ

3

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

trait Wrapper[+T] { 
    def unwrap: T 
} 

object Wrapper { 
    def apply[T](implicit w: Wrapper[T]): w.type = w 
} 

trait IO[In] { 
    type Out 

    def out: Out 
} 

implicit def decoder[In]: Wrapper[IO[In] {type Out = String}] = new Wrapper[IO[In] {type Out = String}] { 
    override def unwrap: IO[In] {type Out = String} = new IO[In] { 
    override type Out = String 
    override val out: Out = "yeah" 
    } 
} 

val wrap = Wrapper[IO[String]] 
val io = wrap.unwrap 
val out: String = io.out 

Самое главное, чтобы изменить тип возвращаемого значения метода apply к w.type. Таким образом сохраняется полный тип w (включая все уточнения). Если вы напишете Wrapper[T] в качестве образца, и вы запросите Wrapper[T] за T, равный IO[String], вы получите Wrapper[IO[String]], и все дополнительные знания, такие как {type Out = String}, будут утеряны.

Второй: в val io: IO[String] = wrap.unwrap вы говорите, что io является IO[String]. Опять же, все лишние знания теряются. Поэтому просто дайте компилятору вывести тип io.

Другое дело: если вы не хотите, чтобы Wrapper был ковариантным в T, вы можете просто отказаться от аннотации отклонения и изменить свой метод apply.

trait Wrapper[T] { 
    def unwrap: T 
} 

object Wrapper { 
    def apply[T](implicit w: Wrapper[_ <: T]): w.type = w 
} 

Таким образом, компилятор все еще знает, что он должен искать подтипIO[String], если вы звоните Wrapper.apply[IO[String]]. Потому что IO[String]{type out = String} является подтипом IO[String], они не равны.

+0

Пятно на. Благодаря :) – eirirlar

1

Не ясно, что вы пытаетесь достичь, но что решить проблему? (обратите внимание на -T в обертке)

object ImplicitWrappedTraitWithType { 
    class Wrapper[-T] 
    object Wrapper { 
    def apply[T](implicit w: Wrapper[T]): Wrapper[T] = w 
    } 
    trait IO[In] { 
    type Out 
    } 
    implicit def decoder[In]: Wrapper[IO[In]] = null 


} 
import ImplicitWrappedTraitWithType._ 

trait IOString[In] extends IO[In] { 
    type Out = String 
} 
//client code 
Wrapper[IOString[Int]] 

Я не буду ставить никаких ограничений на Out типа при попытке найти неявный декодер для него.

ли определяет пользователь его собственный декодер, и в этом случае вы не заботитесь о In и Out, или у вас есть несколько основных декодеров и вы обеспечиваете его, например: IO [Int, String], IO [Int, Boolean ] и т. д.

+0

-T ничего не сделал относительно компиляции. Однако это заставило меня попробовать + T, который «работал» - сортировка. Я немного обновляю этот вопрос, хотя я начинаю подозревать, что у меня нет решения. – eirirlar

+0

Возможно, вы изменили свой код тем временем. Пример, который вы публикуете здесь, который я реорганизовал немного, не будет работать с T или + T, только с -T. В любом случае, я вижу, что вы сделали еще один маршрут и обнаружили, что я лучше подошел. Повеселись! ;-) – Renato