2013-08-19 129 views
6

沿this question線的最大常見的亞型,我試圖找到一種方式來獲得Scala編譯器來推斷兩種類型的最大常見的亞型A和B.找到兩個斯卡拉類型

喜歡的東西「A無B」,其中所述的定義是:

(A without B = C) === (A = C with B) 

,或者不返回C,一個功能類型,其中:

編輯:

A <: C && C <:!< B 

ie。 A是C的亞型,C不是B的亞型

事實上,我期望有人會指出,這是不一樣的「最大的共同亞型」,因爲我實際上並不需要A <: B

用法:

trait Syntax 

trait ANYSYNTAX extends Syntax 
trait NUMERIC extends ANYSYNTAX 
trait DISCRETE extends ANYSYNTAX 
trait POSITIVE extends ANYSYNTAX 
trait CONST extends ANYSYNTAX  
type NUMCONST = NUMERIC with CONST 
type POSCONST = POSITIVE with CONST 
type ORDINALCONST = DISCRETE with CONST 
type INTEGER = NUMERIC with DISCRETE 
type POSNUM = POSITIVE with NUMERIC 
type POSINT = POSNUM with INTEGER 
type INTCONST = INTEGER with NUMCONST with ORDINALCONST 
type POSNUMCONST = POSNUM with POSCONST with NUMCONST 
type POSINTCONST = POSNUMCONST with INTCONST with POSINT 

然後我想是能夠傳播類型的限制,具體如下:

abstract class Expression[+R](val args: Expression[_]*) 

case class Add[A <: R, R <: NUMERIC](arg1: Expression[A], arg2: Expression[A]) extends Expression[R] { 
case class Subtract[A <: R, R : A without POSITIVE](arg1: Expression[A], arg2: Expression[A]) extends Expression[R] { 
case class Multiply[A <: R, R <: NUMERIC](arg1: Expression[A], arg2: Expression[A]) extends Expression[R]{ 
case class Divide[A <: R, R : A without DISCRETE](arg1: Expression[A], arg2: Expression[A]) extends Expression[R] { 

我一直在試圖拿出東西借來使用某種類型的約束從其他答案:

sealed class =!=[A,B] 

trait LowerPriorityImplicits { 
    implicit def equal[A]: =!=[A, A] = sys.error("should not be called") 
} 
object =!= extends LowerPriorityImplicits { 
    implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] = 
    if (same != null) sys.error("should not be called explicitly with same type") 
    else new =!=[A,B] 
} 

// Encoding for "A is not a subtype of B" 
trait <:!<[A, B] 

// Uses ambiguity to rule out the cases we're trying to exclude 
implicit def nsub[A, B] : A <:!< B = null 
implicit def nsubAmbig1[A, B >: A] : A <:!< B = null 
implicit def nsubAmbig2[A, B >: A] : A <:!< B = null 

我有一些測試用例:

implicitly[POSINT <:!< CONST] 
implicitly[POSITIVE <:!< OPINION] 
implicitly[DOGMA <:!< CONST] 

implicitly[POSINTCONST <:< POSITIVE with CONST] 
implicitly[POSINTCONST <:< POSCONST] 
implicitly[POSITIVE with CONST <:!< POSINTCONST] 

implicitly[POSITIVE =:= POSCONST without CONST] 
implicitly[NUMERIC =:= INTEGER without DISCRETE] 
implicitly[POSINT =:= POSINTCONST without CONST] 

這些應該失敗:

implicitly[POSINT =:= POSINTCONST without OPINION] 
implicitly[POSINT with OPINION =!= POSINTCONST without OPINION] 
+0

我不確定我是否理解你的定義。聽起來好像是'A <:B',然後'C'不存在,否則'C'只是'A'。 –

+0

@TravisBrown例如,'C:POSINT','B:CONST'。然後'A:C與B' = POSINTCONST。根據我的第一個定義,'沒有CONST的POSINTCONST =:= POSINT'。如果另一方面是'A <:! RealName

+0

其實@Travis我在我的第二個定義中犯了一個錯誤(我希望現在修復了)。 – RealName

回答

1

好以後隨機撲鍵盤了很多,讀書,就像我能理解有關類型的限制,這就是我想出了:

// A without B is C 
sealed abstract class isWithout[A, B, C] 

object Syntax { 

    implicit def composedWithout[A <: C, B, C](implicit ev: C <:!< B): isWithout[A, B, C] = new isWithout[A, B, C] { 
    def apply(a: A) = a 
    } 

    type without[A, B] = { 
    type l[C] = isWithout[A, B, C] 
    } 
} 

測試,它似乎工作:

implicitly[isWithout[POSCONST, POSITIVE, CONST]] 
implicitly[isWithout[POSINTCONST, DISCRETE, POSNUMCONST]] 
implicitly[isWithout[POSINTCONST, DISCRETE, POSITIVE]] 
implicitly[isWithout[POSNUM, CONST, POSNUM]] 
implicitly[isWithout[POSCONST, CONST, POSITIVE ]] 
implicitly[isWithout[POSCONST, POSITIVE, CONST ]] 
implicitly[isWithout[INTEGER, DISCRETE, NUMERIC ]] 
implicitly[isWithout[POSINTCONST, CONST, POSINT ]] 

而失敗時,它應該:

implicitly[isWithout[POSINTCONST, INTCONST, POSINTCONST]] 
implicitly[isWithout[NUMERIC, ANYSYNTAX, ANYSYNTAX]] 
implicitly[isWithout[INTEGER, POSITIVE, POSINT]] 
implicitly[isWithout[POSNUM, DISCRETE, POSCONST]] 

implicitly得到編譯ŧ o在當前隱式作用域中尋找一個隱式函數,它可以產生所需類型的對象(在這種情況下,該類的一個實例是isWithout)。如果它發現一個滿足類型簽名,然後編譯(我認爲這不重要在類中定義的apply方法返回)。重要的一點是類型簽名,它使用問題中提到的<:!<,並從Miles中借用另一個SO答案。

這種類型的簽名表示:A是C的子類型和C不能是B的子類型的替代版本(對應於問題的第一個定義)將是:

implicit def composedWithout[A <: C with B, B, C](implicit ev: C <:!< B): isWithout[A, B, C] = new isWithout[A, B, C] { 
    def apply(a: A, b: B) = a 
} 

這可以在幾個方式使用:

  1. 要檢查類型層次(即測試用例。)的有效性,如圖所示與上述使用的implicitly

  2. 要指定的方法參數的類型:

    def test[R : without[POSINTCONST, DISCRETE]#l](v: R) = v

    注意,這裏使用的類型的投影without#l[C] = isWithout[A, B, C]作爲結合的上下文,編譯器desugars到:

    def test[R](v: R)(implicit $ev0: isWithout[POSINTCONST, DISCRETE, R]) = v 
    

    因此它要求指定的隱式在範圍內。

  3. 作爲一種約束,如在原來的問題要求:

    case class Subtract[A <: R, R <: A without POSITIVE](arg1: Expression[A], arg2: Expression[A]) extends BinaryPrimitive[A, R](arg1, arg2)

    這將編譯,雖然我承認我還沒有遇到任何事情,所以可能沒有做什麼,我認爲它在做什麼。

3

聽起來像是你想要的斯卡拉類型的最小上限(LUB)?我希望邁爾斯的無形圖書館獲得靈感,他們實際上有LUBConstraint

或者如果你想要更大的下界(GLB)恐怕我不得不引用你使用宏定義,你可以得到LUB或GLB,參見Types

+1

Lubs和glbs也可以使用運行時反射來計算。 –

+0

@wheaties我已經看到無形和「看着」它,但我覺得它很難穿透。我相信GLB是我想要的,這個鏈接可能會有用,但我希望得到更詳細的答案。 – RealName

+0

@Eugene運行時反射會很好,因爲我最終希望能夠在運行時構建新的表達式。 – RealName