Тип союза с верхней границей

Я следовал методу, представленному в принятом ответе на этот вопрос Как определить "тип дизъюнкции" (типы объединения)?, чтобы поддерживать проверку типа для многотипного параметра для метода.

Неявные "доказательства"

@implicitNotFound(msg="Only String, Array[Byte] and InputStream are supported")
  sealed class Input[T]
  object Input{
    implicit object ByteArrayWitness extends Input[Array[Byte]]
    implicit object StringWitness extends Input[String]
    implicit object InputStreamWitness extends Input[InputStream]
  }

Метод API

def foo[T: Input](param: T) =
  param match {
    case x: String => //...
    case x: Array[Byte] => //...
    case x: InputStream => //...
    case _ => throw new UnsupportedOperationException(s"not implemented for type ${param.getClass}")
  }

Проблема

этот компилирует

foo("test")
foo(Array[Byte](123.toByte))

но это не так (потому что это не конкретный InputStream)

foo(new ByteArrayInputStream("abc".getBytes("UTF-8")))

Мне нужно передать его точному супер-типу, чтобы он работал (это компилируется)

foo(new ByteArrayInputStream("abc".getBytes("UTF-8")).asInstanceOf[InputStream])

Есть ли способ изменить

    implicit object InputStreamWitness extends Input[InputStream]

Итак, это доказательство всего, что распространяется на InputStream? У меня есть ощущение, что есть какая-то верхняя граница <: нотации, чтобы подключиться где-то, я просто не знаю, где...

Или это, когда на помощь приходит "сумасшедший материал исчисления лямбды" от самого высокого проголосовавшего ответа на вышеупомянутый вопрос?

Ответ 1

Сделайте Input contra variant в типе T как: Input[-T], это означает, что если A является супер-типом B, то вход [B] является супер-типом ввода [A] (обратное "наследование" ), В вашем случае это просто означает, что Input [InputStream] знает, как обрабатывать все типы ввода подкласса InputStream (например, ByteArrayInputStream)

Мне действительно нравится объяснение контравариантности Рекса Керра в этом вопросе. Но есть много других.