Я думаю, что вы должны отделить определение контейнера от определения типов, приемлемых для самого контейнера.
Прежде всего, скажем (например), что S - это String, а T - фиктивный класс.
class A
class B extends A
type T = A
type S = String
Теперь давайте воспользуемся шаблоном класса типов, чтобы определить S и подклассы T как приемлемый контент для нашего контейнера:
sealed class AcceptableContent[X] private()
object AcceptableContent {
implicit object SAcceptable extends AcceptableContent [S]
implicit def TAcceptable[U <: T] = new AcceptableContent[U]
}
теперь класс Container можно определить так:
class Container[R : AcceptableContent](content: R)
ограниченный контекстом : AcceptableContent
говорит, что вы можете принять R только в том случае, если в области видимости есть неявный AcceptableContent [R], который вам нужен.
На самом деле, сейчас:
scala> new Container("test")
res0: Container[java.lang.String] = Container@1d1fceed
scala> new Container(new A)
res1: Container[A] = Container@631803fb
scala> new Container(new B)
res2: Container[B] = Container@67446579
scala> new Container(true) // Ok, Container accepts String, A, B but not Boolean
<console>:12: error: could not find implicit value for evidence parameter of type AcceptableContent[Boolean]
Итак, invoke теперь становится:
def invoke[N : AcceptableContent](f: String => N) : Container[N] = new Container(f("test"))