मैं सोच रहा हूं कि वैकल्पिक उपप्रकारों के साथ प्रथम श्रेणी के डिसऑन टाइप प्रकार एक सील सुपरटेप है, और इन वैकल्पिक उपप्रकारों के लिए वांछित प्रकार के विच्छेदन से / के लिए अंतर्निहित रूपांतरण हैं।
मुझे लगता है कि यह मील्स सबिन के समाधान के 33 - 36 टिप्पणियों को संबोधित करता है , इसलिए प्रथम श्रेणी का प्रकार जिसे उपयोग स्थल पर नियोजित किया जा सकता है, लेकिन मैंने इसका परीक्षण नहीं किया।
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
एक समस्या यह है कि स्कैला मिलान के संदर्भ में, (और से ) के IntOfIntOrString
लिए एक अंतर्निहित रूपांतरण के मामले में नियोजित नहीं करेगा , इसलिए निकालने वाले को परिभाषित करना चाहिए और इसके बजाय उपयोग करना चाहिए ।Int
StringOfIntOrString
String
case Int(i)
case i : Int
ADD: मैंने अपने ब्लॉग पर मीलों सबिन का जवाब इस प्रकार दिया। शायद या तो कई सुधार हैं:
- यह उपयोग या परिभाषा साइट पर किसी भी अतिरिक्त शोर के बिना, 2 से अधिक प्रकारों तक फैली हुई है।
- तर्क को स्पष्ट रूप से बॉक्सिंग किया जाता है, जैसे कि जरूरत नहीं है
size(Left(2))
या size(Right("test"))
।
- पैटर्न मिलान का सिंटैक्स अनुमानित रूप से अनबॉक्स है।
- बॉक्सिंग और अनबॉक्सिंग को जेवीएम हॉटस्पॉट द्वारा अनुकूलित किया जा सकता है।
- वाक्यविन्यास भविष्य के प्रथम श्रेणी के यूनियन प्रकार द्वारा अपनाया जा सकता है, इसलिए प्रवास शायद सहज हो सकता है? शायद संघ प्रकार के नाम के लिए, इसके
V
बजाय Or
, उदाहरण के लिए IntVString
, ` Int |v| String
`, ` Int or String
`, या मेरे पसंदीदा ` Int|String
` का उपयोग करना बेहतर होगा ?
अद्यतन: उपर्युक्त पैटर्न के लिए अस्वीकृति का तार्किक निषेध इस प्रकार है, और मैंने माइल्स सबिन के ब्लॉग पर एक वैकल्पिक (और शायद अधिक उपयोगी) पैटर्न जोड़ा ।
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)
उत्तर प्रदेश: माइल साबिन के समाधान के बारे में 23 और 35 टिप्पणियों के बारे में , यहाँ एक तरह से उपयोग स्थल पर संघ की घोषणा की गई है। ध्यान दें कि यह पहले स्तर के बाद अनबॉक्स है, अर्थात इसमें किसी भी प्रकार के किसी भी प्रकार के डिस्पेंस करने के लिए एक्स्टेंसिबल होने का फायदा है , जबकि Either
नेस्टेड बॉक्सिंग की आवश्यकता है और मेरी पूर्व टिप्पणी में प्रतिमान 41 नहीं था। दूसरे शब्दों में, एक D[Int ∨ String]
करने के लिए (यानी का एक उपप्रकार) के लिए उपलब्ध है 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]])
^
जाहिर तौर पर स्काला कंपाइलर में तीन बग होते हैं।
- यह गंतव्य प्रकार की गड़बड़ी में पहले प्रकार के बाद किसी भी प्रकार के लिए सही निहित फ़ंक्शन का चयन नहीं करेगा।
- यह
D[¬[Double]]
मामले को मैच से बाहर नहीं करता है ।
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
सहसंयोजक स्थिति में अनुमति नहीं देगा । एक तर्क हो सकता है कि यह एक बग है क्योंकि हम चाहते हैं कि सभी सबूत हैं, हम कभी भी फ़ंक्शन में सबूत तक नहीं पहुंचते हैं। और मैं पसंद नहीं परीक्षण के लिए बनाया case _
में get
विधि, तो मैं एक Unbox नहीं करनी होगी Option
में match
में size()
।
05 मार्च, 2012: पूर्व अद्यतन में सुधार की आवश्यकता है। माइल्स सबिन के समाधान ने सबटाइपिंग के साथ सही ढंग से काम किया।
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]]
^
मेरे पूर्व अद्यतन के प्रस्ताव (प्रथम श्रेणी के संघ प्रकार के पास) ने सबटाइपिंग को तोड़ दिया।
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)]]
^
समस्या यह है कि दोनों सहसंयोजक (वापसी प्रकार) और contravariant (फ़ंक्शन इनपुट, या इस मामले में फ़ंक्शन का रिटर्न मान जो फ़ंक्शन इनपुट) स्थिति A
में (() => A) => A
प्रकट होता है, इस प्रकार प्रतिस्थापन केवल अपरिवर्तनीय हो सकते हैं।
ध्यान दें कि A => Nothing
केवल इसलिए आवश्यक है क्योंकि हम A
कंट्रावेरिएंट स्थिति में चाहते हैं , ताकि सुपरपाइप्स A
न तो सबटिप हैं D[¬[A]]
और न ही D[¬[A] with ¬[U]]
( यह भी देखें )। चूँकि हमें केवल दोहरे विरोधाभास की आवश्यकता होती है, इसलिए हम मीलों के समाधान के समतुल्य प्राप्त कर सकते हैं, भले ही हम ¬
और को त्याग सकें ∨
।
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]]]
^
तो पूरा तय है।
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]
}
ध्यान दें कि स्केला में पहले के 2 कीड़े बने रहते हैं, लेकिन तीसरे को टाला जाता T
है क्योंकि अब उप-प्रकार होने के लिए विवश है A
।
हम उप-निर्माण कार्यों की पुष्टि कर सकते हैं।
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
मैं सोच कर दिया गया है कि प्रथम श्रेणी के चौराहे प्रकार बहुत महत्वपूर्ण हैं, के लिए दोनों कारणों सीलोन उन्हें है , और क्योंकि बजाय subsuming को Any
जो साधन एक साथ unboxing match
उम्मीद प्रकार पर एक रनटाइम त्रुटि उत्पन्न कर सकते हैं, एक (के unboxing विषम संग्रह युक्त a) डिस्जंक्शन को चेक किया जा सकता है (Scala को मेरे द्वारा नोट किए गए बग्स को ठीक करना है)। यूनियन की तुलना में अधिक स्पष्ट हैं का उपयोग कर की जटिलता प्रयोगात्मक HList की metascala विषम संग्रह के लिए।
class StringOrInt[T]
बनाया गया हैsealed
, तो आपके द्वारा संदर्भित "लीक" (निश्चित रूप से, यह क्लाइंट कोड द्वाराStringOrInt[Boolean]
" बनाकर साइड-स्टेप किया जा सकता है ) प्लग किया गया है, कम से कम यदिStringOrInt
इसकी स्वयं की फ़ाइल में रहता है। फिर गवाह वस्तुओं को उसी तरह से परिभाषित किया जाना चाहिए जैसा किStringOrInt
।