Is it possible to find a common supertype on type-system level in Scala?

前端 未结 3 1477
梦谈多话
梦谈多话 2020-12-19 02:53

Is it possible to make a type-alias (or something equivalent) in Scala that takes two parameters and returns their common supertype? In other words, I\'m trying to find some

3条回答
  •  醉话见心
    2020-12-19 03:30

    I can give you a trait CommonSupertype[A, B] and an implicit generator function, so you can just require an implicit instance of this trait wherever you need it, and it will contain the common supertype (as a dependent type).

    This is not my idea, it's actually adapted ever so slightly from this post by Miles Sabin.

    The only change I've made is that, while he is using ¬¬[C] <:< (A ∨ B) as evidence that a type C is a subtype of either A or B, I've reversed the subtyping direction (so: (A ∨ B) <:< ¬¬[C]) to check that both A and B are subtypes of C.

    import scala.reflect.ClassTag
    
    object Main extends App {
      type ¬[A] = A => Nothing
      type ∨[T, U] = ¬[¬[T] with ¬[U]]
      type ¬¬[A] = ¬[¬[A]]
    
      trait CommonSupertype[A, B] {
        type λ
        def tag: ClassTag[λ]
      }
      // The ClassTag is only so I can get ahold of the type's name at runtime
      implicit def commonSupertype[A, B, C : ClassTag](implicit C: (A ∨ B) <:< ¬¬[C]): CommonSupertype[A, B] { type λ = C } =
        new CommonSupertype[A, B] { type λ = C; def tag = implicitly[ClassTag[C]] }
    
      trait Pet
      class Dog extends Pet
      class Cat extends Pet
      def check[A, B](implicit x: CommonSupertype[A, B]) = {
        // This just prints the common type, but you could use the type (x.λ) directly
        println(x.tag.toString())
      }
      check[Dog, Cat]
      check[Dog, Double]
    }
    

    Gives us:

    Main.Pet
    Any
    

提交回复
热议问题