简体   繁体   English

带有子类型的scala中的联合类型:A | B <:A | B | C.

[英]union types in scala with subtyping: A|B <: A|B|C

I would like to have a A|B type to be the subtype of A|B|C . 我想将A|B类型作为A|B|C的子类型。 Is that possible to encode in Scala ? 这可能在Scala中编码吗? If yes, how ? 如果有,怎么样?

I was hoping that I can make implicitly[¬¬[IF] <:< T] compile below (original code here ), but it does not. 我希望我可以在下面implicitly[¬¬[IF] <:< T]编译( 这里是原始代码),但事实并非如此。 Is there a way to fix this code to allow subtyping ? 有没有办法修复此代码以允许子类型?

object NUnion{
  type ¬¬[A] = ¬[¬[A]]

  type ¬[A] = A => Nothing
  trait Disj[T] {
    type or[S] = Disj[T with ¬[S]]
    type apply = ¬[T]
  }

  // for convenience
  type disj[T] = { type or[S] = Disj[¬[T]]#or[S] }


  type T = disj[Int]#or[Float]#or[String]#apply
  type IF = disj[Int]#or[Float]#apply
  implicitly[¬¬[Int] <:< T] // works
  // implicitly[¬¬[Double] <:< T] // doesn't work
  // implicitly[¬¬[IF] <:< T] // doesn't work - but it should

} }

I also tried this (from here ): 我也试过这个(从这里 ):

object Kerr{
  def f[A](a: A)(implicit ev: (Int with String with Boolean) <:< A) = a match {
     case i: Int => i + 1
     case s: String => s.length
  }

  f(1) //works
  f("bla") // works
  def g[R]()(implicit ev: (Int with String with Boolean) <:< R):R = "go" // does not work

}

but here I cannot make a union type "first-class" they can only exist as argument types, not as return types. 但是在这里我不能使联合类型“第一类”它们只能作为参数类型存在,而不能作为返回类型存在。

Same problem with this approach : 这种方法也有同样的问题:

object Map{
  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]"
    }


    def geza[A : (∅ ∨ String ∨ Int ∨ List[Int])#Member] : A = "45" // does not work 


    foo(geza)

    foo(42)
    foo("bar")
    foo(List(1, 2, 3))
//    foo(42d) // error
//    foo[Any](???) // error
  }

}

The union type of Scala.js ( source and tests ) supports A | B Scala.js的联合类型( 测试 )支持A | B A | B subtype of A | B | C A | B | C A | B亚型 A | B | C A | B | C . A | B | C It even supports permutations like A | B 它甚至支持像A | B这样A | B排列 A | B subtype of B | C | A A | B的亚型B | C | A B | C | A B | C | A . B | C | A

Your first approach works OK for me. 你的第一种方法对我来说很好。 It also works with permutations of types. 它也适用于类型的排列。

type IFS = disj[Int]#or[Float]#or[String]#apply
type IF = disj[Int]#or[Float]#apply
type IS = disj[Int]#or[String]#apply
type IFD = disj[Int]#or[Float]#or[Double]#apply
type FI = disj[Float]#or[Int]#apply

scala> implicitly[IF <:< IFS]
res0: <:<[IF,IFS] = <function1>

scala> implicitly[IS <:< IFS]
res1: <:<[IS,IFS] = <function1>

scala> implicitly[FI <:< IFS]
res2: <:<[FI,IFS] = <function1>

scala> implicitly[IFD <:< IFS]
<console>:18: error: Cannot prove that IFD <:< IFS.
       implicitly[IFD <:< IFS]

Of course, you should not lift IF into a union type with ¬¬[IF] , because it's already a union type. 当然,你不应该将IF提升为具有¬¬[IF]的联合类型,因为它已经是联合类型。 You need to do ¬¬[Int] , only because Int is not a union type in this approach. 你需要做¬¬[Int] ,因为在这种方法中Int不是联合类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM