2017-07-22 14 views
4

A|BタイプをA|B|Cのサブタイプにしたいと考えています。 Scalaでエンコードすることは可能ですか?はいの場合、どうですか?サブタイプのスカラー型の結合型:A | B <:A | B | C

私はimplicitly[¬¬[IF] <:< T](元のコードhere)をコンパイルできると期待していましたが、そうではありません。サブタイプを許可するためにこのコードを修正する方法はありますか?

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 

}

私も(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 

} 

が、ここで私は、彼らが唯一の引数の型として存在することができるユニオン型「ファーストクラス」ではないことはできません戻り値の型としてthisアプローチと

同じ問題:

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 
    } 

} 
+0

関連:https://contributors.scala-lang.org/t/dotty-style-union-types-in-scala/733/2 – jhegedus

答えて

1

Scala.js(sourcetests)のユニオン型はA | B | CA | Bサブタイプをサポートしています。それはA | BサブタイプB | C | Aのような並べ替えをサポートします。

+0

素晴らしいですが、Scalaはこれをサーバー側でサポートできないと思いますか?または、サーバー側でも使用できますか? Scala.jsに固有のものを使用していますか?これはサーバー側でもちょっとしたやり方でうまくいくように思えます...そうですか? – jhegedus

+1

これは主にサーバー側で実行できますが、 'sealed 'の代わりに抽象' type | [A、B] 'を使用しなければならないので、その消去は' Object'で成功する。これには一つの欠点があります。暗黙のスコープに自動的に持ち込まれるような暗黙のオブジェクトがないということです。これは、あなたが "サブタイピング関係"を保持する必要がある場所では、インポートが必要であることを意味します。 Scala.jsの中では、 'A | B '。 – sjrd

+0

ありがとう、私はこの作品を作ることができ、Scala.jsとScalaの間のこの消しゴムの違いについて考えてみる必要があります。 – jhegedus

1

あなたの最初のアプローチは私にとってはうまくいきます。また、型の順列でも動作します。もちろん

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] 

それはすでにユニオンタイプだから、あなたは、¬¬[IF]との連合型にIFを持ち上げてはいけません。このアプローチではIntがユニオンタイプではないため、¬¬[Int]を実行する必要があります。

+0

面白い、ありがとう!関数内で戻り値の型として 'IF'を使用できますか? – jhegedus

関連する問題