আমি ভাবছি যে প্রথম শ্রেণির বিচ্ছিন্নতাটি হ'ল একটি সিলড সুপার টাইপ, বিকল্প সাব টাইপগুলি সহ এবং এই বিকল্প সাব-টাইপের সাথে কাঙ্ক্ষিত ধরণের সংশ্লেষের / থেকে অন্তর্নিহিত রূপান্তর।
আমি এই ঠিকানাগুলিতে মাইলস সাবিনের সমাধানের 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
একটা সমস্যা Scala ক্ষেত্রে ম্যাচিং প্রেক্ষাপটে নিয়োগ করে না, থেকে একটি অন্তর্নিহিত রূপান্তর হবে IntOfIntOrString
থেকে Int
(এবং StringOfIntOrString
করতে String
), তাই extractors এবং সংজ্ঞায়িত ব্যবহার করা আবশ্যক case Int(i)
পরিবর্তে case i : Int
।
ADD: আমি মাইলস সাবিনকে তার ব্লগে নিম্নরূপ প্রতিক্রিয়া জানিয়েছি। সম্ভবত একাধিক উন্নতি হতে পারে:
- এটি ব্যবহার বা সংজ্ঞা সাইটে কোনও অতিরিক্ত শব্দ ছাড়াই এটি 2 টিরও বেশি প্রকারের মধ্যে প্রসারিত।
- যুক্তিগুলি স্পষ্টভাবে বক্স করা হয়, যেমন প্রয়োজন হয় না
size(Left(2))
বা size(Right("test"))
।
- প্যাটার্ন মিলের সিনট্যাক্স সুস্পষ্টভাবে আনবক্সড হয়।
- বক্সিং এবং আনবক্সিং জেভিএম হটস্পট দ্বারা অপ্টিমাইজ করা যেতে পারে।
- ভবিষ্যতের প্রথম শ্রেণীর ইউনিয়ন ধরণের সিনট্যাক্সটি এমনটি হতে পারে, যাতে মাইগ্রেশন সম্ভবত বিরামহীন হতে পারে? সম্ভবত ইউনিয়নের টাইপের নামের
V
জন্য Or
, উদাহরণস্বরূপ IntVString
, ` Int |v| String
`, ` Int or String
`, বা আমার প্রিয় `এর পরিবর্তে ব্যবহার করা ভাল wouldInt|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
নেস্টেড বক্সিং প্রয়োজন এবং আমার পূর্ববর্তী মন্তব্যে d১ দৃষ্টান্তটি এক্সটেনসিবল ছিল না। অন্য কথায়, একটি 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)]]
^
সমস্যা হল A
মধ্যে(() => A) => A
কোভেরিয়েন্ট (রিটার্ন টাইপ) এবং কনট্রোভারেন্ট (ফাংশন ইনপুট, বা এক্ষেত্রে ফাংশনের রিটার্ন ভ্যালু যা একটি ফাংশন ইনপুট) উভয় প্রদর্শিত হয়, সুতরাং প্রতিস্থাপনগুলি কেবল অদম্য হতে পারে।
লক্ষ্য করুন A => Nothing
প্রয়োজনীয় শুধুমাত্র কারণ আমরা চাই A
contravariant ভঙ্গিমায়, যাতে তিনি যে supertypes 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 বাগগুলি মনে রাখবেন, তবে 3 য়টি এড়িয়ে যাওয়া এড়ানো হয়েছে যেহেতু 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
আমি ভাবছিলাম যে প্রথম-শ্রেণীর ছেদগুলির ধরণগুলি অত্যন্ত গুরুত্বপূর্ণ, উভয় কারণে সিলোন রয়েছে এবং এটির পরিবর্তে যার অর্থ একটি প্রত্যাশিত ধরণের সাথে আনবক্সিং একটি রানটাইম ত্রুটি তৈরি করতে পারে , একটিটির আনবক্সিং (একটি ভিন্নধর্মী সংগ্রহ রয়েছে) ক) বিচ্ছিন্নতা যাচাই করে টাইপ করা যেতে পারে (স্ক্যালাগুলি আমি উল্লেখ করা বাগগুলি ঠিক করতে হবে)। ইউনিয়ন চেয়ে বেশি সহজবোধ্য হয় ব্যবহারের জটিলতা পরীক্ষামূলক HList এর metascala ভিন্নধর্মী সংগ্রহের জন্য।Any
match
class StringOrInt[T]
তৈরি করা হয়sealed
, তবে আপনি যে "ফুটো" উল্লেখ করেছেন ("অবশ্যই এটি ক্লায়েন্ট কোড দ্বারাStringOrInt[Boolean]
" তৈরি করে পাশের পদক্ষেপে থাকতে পারে )) প্লাগ করা আছে, কমপক্ষে যদিStringOrInt
তার নিজস্ব কোনও ফাইল থাকে res তারপরে সাক্ষী অবজেক্টগুলি অবশ্যই একই সূত্রে সংজ্ঞায়িত করা উচিতStringOrInt
।