Birinci sınıf ayrık tipin, alternatif alt tiplerle ve bu alternatif alt tiplere istenen ayrıklık tiplerine / bu tiplerden örtük dönüşümlerle kapalı bir süper tip olduğunu düşünüyorum.
Bu , Miles Sabin'in çözümünün 33 - 36 yorumlarını ele aldığını varsayıyorum , bu nedenle kullanım sitesinde kullanılabilecek birinci sınıf türü, ancak test etmedim.
sealed trait IntOrString
case class IntOfIntOrString( v:Int ) extends IntOrString
case class StringOfIntOrString( v:String ) extends IntOrString
implicit def IntToIntOfIntOrString( v:Int ) = new IntOfIntOrString(v)
implicit def StringToStringOfIntOrString( v:String ) = new StringOfIntOrString(v)
object Int {
def unapply( t : IntOrString ) : Option[Int] = t match {
case v : IntOfIntOrString => Some( v.v )
case _ => None
}
}
object String {
def unapply( t : IntOrString ) : Option[String] = t match {
case v : StringOfIntOrString => Some( v.v )
case _ => None
}
}
def size( t : IntOrString ) = t match {
case Int(i) => i
case String(s) => s.length
}
scala> size("test")
res0: Int = 4
scala> size(2)
res1: Int = 2
Bir sorun, Scala'nın eşleştirme bağlamında işe yaramayacağı, ' IntOfIntOrString
den Int
(ve' StringOfIntOrString
ye String
) örtük bir dönüşüm olduğu için çıkarıcılar tanımlaması ve case Int(i)
bunun yerine kullanılması gerekir case i : Int
.
ADD: Miles Sabin'e blogunda şöyle cevap verdim. Belki de İkisi üzerinde birkaç gelişme var:
- Kullanım veya tanımlama sitesinde herhangi bir ek gürültü olmadan 2'den fazla türe uzanır.
- Bağımsız değişkenler örtük olarak kutlanır, örn . Gerek yok
size(Left(2))
veya size(Right("test"))
.
- Desen eşleşmesinin sözdizimi örtülü olarak kutudan çıkarılır.
- Boks ve kutudan çıkarma JVM etkin noktası tarafından optimize edilebilir.
- Sözdizimi, gelecekteki birinci sınıf sendika türü tarafından benimsenen sözdizimi olabilir, bu nedenle göç belki de kesintisiz olabilir mi? Belki sendika türü adı için , örneğin ` `, ` ` veya en sevdiğim ` `
V
yerine kullanmak daha iyi olur ?Or
IntVString
Int |v| String
Int or String
Int|String
GÜNCELLEME: Yukarıdaki örüntü için kopukluğun mantıksal olarak reddedilmesi takip eder ve Miles Sabin'in bloguna alternatif (ve muhtemelen daha kullanışlı) bir örüntü ekledim .
sealed trait `Int or String`
sealed trait `not an Int or String`
sealed trait `Int|String`[T,E]
case class `IntOf(Int|String)`( v:Int ) extends `Int|String`[Int,`Int or String`]
case class `StringOf(Int|String)`( v:String ) extends `Int|String`[String,`Int or String`]
case class `NotAn(Int|String)`[T]( v:T ) extends `Int|String`[T,`not an Int or String`]
implicit def `IntTo(IntOf(Int|String))`( v:Int ) = new `IntOf(Int|String)`(v)
implicit def `StringTo(StringOf(Int|String))`( v:String ) = new `StringOf(Int|String)`(v)
implicit def `AnyTo(NotAn(Int|String))`[T]( v:T ) = new `NotAn(Int|String)`[T](v)
def disjunction[T,E](x: `Int|String`[T,E])(implicit ev: E =:= `Int or String`) = x
def negationOfDisjunction[T,E](x: `Int|String`[T,E])(implicit ev: E =:= `not an Int or String`) = x
scala> disjunction(5)
res0: Int|String[Int,Int or String] = IntOf(Int|String)(5)
scala> disjunction("")
res1: Int|String[String,Int or String] = StringOf(Int|String)()
scala> disjunction(5.0)
error: could not find implicit value for parameter ev: =:=[not an Int or String,Int or String]
disjunction(5.0)
^
scala> negationOfDisjunction(5)
error: could not find implicit value for parameter ev: =:=[Int or String,not an Int or String]
negationOfDisjunction(5)
^
scala> negationOfDisjunction("")
error: could not find implicit value for parameter ev: =:=[Int or String,not an Int or String]
negationOfDisjunction("")
^
scala> negationOfDisjunction(5.0)
res5: Int|String[Double,not an Int or String] = NotAn(Int|String)(5.0)
BAŞKA BİR GÜNCELLEME: Mile Sabin'in çözümünün 23 ve 35. yorumlarıyla ilgili olarak, kullanım sahasında sendika türünü bildirmenin bir yolu. İlk seviyeden sonra kutunun açıldığına dikkat edin, yani avantajın kopmadaki herhangi bir sayı tipine genişletilebilir olması gerekirken, Either
iç içe boksa ihtiyaç duyar ve önceki yorumumdaki 41 paradigma genişletilemezdi. Başka bir deyişle, a D[Int ∨ String]
, a'ya atanabilir (yani bir alt tipidir) D[Int ∨ String ∨ Double]
.
type ¬[A] = (() => A) => A
type ∨[T, U] = ¬[T] with ¬[U]
class D[-A](v: A) {
def get[T](f: (() => T)) = v match {
case x : ¬[T] => x(f)
}
}
def size(t: D[Int ∨ String]) = t match {
case x: D[¬[Int]] => x.get( () => 0 )
case x: D[¬[String]] => x.get( () => "" )
case x: D[¬[Double]] => x.get( () => 0.0 )
}
implicit def neg[A](x: A) = new D[¬[A]]( (f: (() => A)) => x )
scala> size(5)
res0: Any = 5
scala> size("")
error: type mismatch;
found : java.lang.String("")
required: D[?[Int,String]]
size("")
^
scala> size("hi" : D[¬[String]])
res2: Any = hi
scala> size(5.0 : D[¬[Double]])
error: type mismatch;
found : D[(() => Double) => Double]
required: D[?[Int,String]]
size(5.0 : D[?[Double]])
^
Görünüşe göre Scala derleyicisinin üç hatası var.
- Hedef disjunctiondaki ilk türden sonra herhangi bir tür için doğru örtük işlevi seçmez.
- Bu dışlamaz
D[¬[Double]]
maçından dava.
3.
scala> class D[-A](v: A) {
def get[T](f: (() => T))(implicit e: A <:< ¬[T]) = v match {
case x : ¬[T] => x(f)
}
}
error: contravariant type A occurs in covariant position in
type <:<[A,(() => T) => T] of value e
def get[T](f: (() => T))(implicit e: A <:< ?[T]) = v match {
^
A
Derleme kovaryant pozisyonuna izin vermeyeceğinden , get yöntemi giriş türünde doğru şekilde kısıtlanmamıştır . Birisi bunun bir hata olduğunu iddia edebilir, çünkü istediğimiz tek şey kanıttır, fonksiyondaki kanıtlara asla erişemeyiz. Ve ben değil testine seçim yapmış case _
içinde get
ben bir Unbox olmazdı böylece yöntemde Option
dematch
içinde size()
.
05 Mart 2012: Önceki güncellemenin iyileştirilmesi gerekiyor. Miles Sabin'in çözümü alt tiplerle doğru çalıştı.
type ¬[A] = A => Nothing
type ∨[T, U] = ¬[T] with ¬[U]
class Super
class Sub extends Super
scala> implicitly[(Super ∨ String) <:< ¬[Super]]
res0: <:<[?[Super,String],(Super) => Nothing] =
scala> implicitly[(Super ∨ String) <:< ¬[Sub]]
res2: <:<[?[Super,String],(Sub) => Nothing] =
scala> implicitly[(Super ∨ String) <:< ¬[Any]]
error: could not find implicit value for parameter
e: <:<[?[Super,String],(Any) => Nothing]
implicitly[(Super ? String) <:< ?[Any]]
^
Önceki güncellememin önerisi (neredeyse birinci sınıf sendika türü için) alt türlemeyi kırdı.
scala> implicitly[D[¬[Sub]] <:< D[(Super ∨ String)]]
error: could not find implicit value for parameter
e: <:<[D[(() => Sub) => Sub],D[?[Super,String]]]
implicitly[D[?[Sub]] <:< D[(Super ? String)]]
^
Problem şu A
de (() => A) => A
bildirdiğinden (dönüş türü) ve kontravaryant hem görünür pozisyonlar (fonksiyon girişi, veya bu durumda bir fonksiyonu girişi olan fonksiyonunun bir geri dönüş değeri) ve bu nedenle ikameler değişmez olabilir.
Not A => Nothing
istediğimiz tek nedeni gereklidir A
kontravaryant pozisyonda, yani bir supertypes o A
değil alt tipler arasında D[¬[A]]
ne de D[¬[A] with ¬[U]]
( ayrıca bkz ). Biz sadece çift contravariance ihtiyaç beri atmak bile, biz Miles'in çözümü denk elde edebilirsiniz ¬
ve ∨
.
trait D[-A]
scala> implicitly[D[D[Super]] <:< D[D[Super] with D[String]]]
res0: <:<[D[D[Super]],D[D[Super] with D[String]]] =
scala> implicitly[D[D[Sub]] <:< D[D[Super] with D[String]]]
res1: <:<[D[D[Sub]],D[D[Super] with D[String]]] =
scala> implicitly[D[D[Any]] <:< D[D[Super] with D[String]]]
error: could not find implicit value for parameter
e: <:<[D[D[Any]],D[D[Super] with D[String]]]
implicitly[D[D[Any]] <:< D[D[Super] with D[String]]]
^
Yani tam düzeltme.
class D[-A] (v: A) {
def get[T <: A] = v match {
case x: T => x
}
}
implicit def neg[A](x: A) = new D[D[A]]( new D[A](x) )
def size(t: D[D[Int] with D[String]]) = t match {
case x: D[D[Int]] => x.get[D[Int]].get[Int]
case x: D[D[String]] => x.get[D[String]].get[String]
case x: D[D[Double]] => x.get[D[Double]].get[Double]
}
Scala'daki önceki 2 hatanın kaldığına dikkat edin, ancak 3. hatadan kaçınılmalıdır. T
şimdi alt tip olarak kısıtlandığı içinA
.
Alt tip çalışmaları onaylayabiliriz.
def size(t: D[D[Super] with D[String]]) = t match {
case x: D[D[Super]] => x.get[D[Super]].get[Super]
case x: D[D[String]] => x.get[D[String]].get[String]
}
scala> size( new Super )
res7: Any = Super@1272e52
scala> size( new Sub )
res8: Any = Sub@1d941d7
Ben birinci sınıf kavşak tipleri, çok önemli olduğunu düşünen olmuştur hem Seylan onları sahip olmasının nedenlerinden yerine çünkü ve subsuming için Any
bir ile unboxing hangi yollarla match
bir çalışma zamanı hatası oluşturabilir beklenen türlerinde, bir (bir kutudan çıkarma heterojen koleksiyonu içeren a) Ayrılma tipi kontrol edilebilir (Scala not ettiğim hataları düzeltmek zorundadır). Sendikalar daha basittir kullanarak karmaşıklığı deneysel hList ait metascala heterojen koleksiyonları için.
class StringOrInt[T]
yapılırsasealed
, bahsettiğiniz "sızıntı" ("Tabii ki, bu birStringOrInt[Boolean]
" oluşturarak istemci kodu tarafından yan basamaklı olabilir "), en azındanStringOrInt
kendi dosyasında bulunuyorsa takılır . O zaman tanık nesneleri aynı sosta tanımlanmalıdırStringOrInt
.