How to define “type disjunction” (union types)?

前端 未结 15 2453
温柔的废话
温柔的废话 2020-11-22 05:52

One way that has been suggested to deal with double definitions of overloaded methods is to replace overloading with pattern matching:

object Bar {
   def fo         


        
15条回答
  •  庸人自扰
    2020-11-22 06:38

    I have sort of stumbled on a relatively clean implementation of n-ary union types by combining the notion of type lists with a simplification of Miles Sabin's work in this area, which someone mentions in another answer.

    Given type ¬[-A] which is contravariant on A, by definition given A <: B we can write ¬[B] <: ¬[A], inverting the ordering of types.

    Given types A, B, and X, we want to express X <: A || X <: B. Applying contravariance, we get ¬[A] <: ¬[X] || ¬[B] <: ¬[X]. This can in turn be expressed as ¬[A] with ¬[B] <: ¬[X] in which one of A or B must be a supertype of X or X itself (think about function arguments).

    object Union {
      import scala.language.higherKinds
    
      sealed trait ¬[-A]
    
      sealed trait TSet {
        type Compound[A]
        type Map[F[_]] <: TSet
      }
    
      sealed trait ∅ extends TSet {
        type Compound[A] = A
        type Map[F[_]] = ∅ 
      }
    
      // Note that this type is left-associative for the sake of concision.
      sealed trait ∨[T <: TSet, H] extends TSet {
        // Given a type of the form `∅ ∨ A ∨ B ∨ ...` and parameter `X`, we want to produce the type
        // `¬[A] with ¬[B] with ... <:< ¬[X]`.
        type Member[X] = T#Map[¬]#Compound[¬[H]] <:< ¬[X]
    
        // This could be generalized as a fold, but for concision we leave it as is.
        type Compound[A] = T#Compound[H with A]
    
        type Map[F[_]] = T#Map[F] ∨ F[H]
      }
    
      def foo[A : (∅ ∨ String ∨ Int ∨ List[Int])#Member](a: A): String = a match {
        case s: String => "String"
        case i: Int => "Int"
        case l: List[_] => "List[Int]"
      }
    
      foo(42)
      foo("bar")
      foo(List(1, 2, 3))
      foo(42d) // error
      foo[Any](???) // error
    }
    

    I did spend some time trying to combine this idea with an upper bound on member types as seen in the TLists of harrah/up, however the implementation of Map with type bounds has thus far proved challenging.

提交回复
热议问题