বিষয়গুলিকে প্রসঙ্গে রাখতে: এই উত্তরটি মূলত অন্য থ্রেডে পোস্ট করা হয়েছিল। আপনি এটি এখানে দেখছেন কারণ দুটি থ্রেড একত্রিত করা হয়েছে। উল্লিখিত থ্রেডে প্রশ্ন বিবৃতিটি নিম্নরূপ ছিল:
এই ধরণের সংজ্ঞা কীভাবে সমাধান করবেন: খাঁটি [({প্রকার? [ক] = (আর, ক)}) #?]?)?
এই ধরনের নির্মাণ ব্যবহার করার কারণগুলি কী কী?
স্নিপড স্ক্যালজ লাইব্রেরি থেকে আসে:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
object Pure {
import Scalaz._
//...
implicit def Tuple2Pure[R: Zero]: Pure[({type ?[a]=(R, a)})#?] = new Pure[({type ?[a]=(R, a)})#?] {
def pure[A](a: => A) = (Ø, a)
}
//...
}
উত্তর:
trait Pure[P[_]] {
def pure[A](a: => A): P[A]
}
বাক্সগুলির মধ্যে একটি আন্ডারস্কোরের পরে P
বোঝায় যে এটি একটি প্রকারের কনস্ট্রাক্টর এক প্রকার নেয় এবং অন্য প্রকারটি প্রদান করে। এই জাতীয় ধরণের কনস্ট্রাক্টরগুলির উদাহরণ: List
, Option
।
List
একটি Int
, একটি কংক্রিট টাইপ দিন এবং এটি আপনাকে দেয় List[Int]
, অন্য কংক্রিটের ধরণ। List
একটি দিন String
এবং এটি আপনাকে দেয় List[String]
। প্রভৃতি
সুতরাং, List
, Option
1. আনুষ্ঠানিকভাবে আমরা বলতে arity ধরণ স্তর ফাংশন হিসেবে বিবেচনা করা যেতে পারে, তারা একটি ধরনের আছে * -> *
। নক্ষত্র একটি প্রকারকে বোঝায়।
এখন Tuple2[_, _]
ধরণের একটি টাইপ কনস্ট্রাক্টর (*, *) -> *
অর্থাৎ নতুন টাইপ পাওয়ার জন্য আপনাকে এটি দুটি প্রকারের দেওয়া দরকার।
যেহেতু তাদের স্বাক্ষর মিলছে না, আপনি প্রতিস্থাপন করতে পারবেন না Tuple2
জন্য P
। আপনার যা করা দরকার তা আংশিকভাবে এর একটি Tuple2
যুক্তিতে প্রয়োগ করা হবে যা আমাদের সাথে ধরণের একটি নির্মাতা দেবে * -> *
এবং আমরা এটির জন্য প্রতিস্থাপন করতে পারি P
।
দুর্ভাগ্যক্রমে স্কালার টাইপ কন্সট্রাক্টরদের আংশিক প্রয়োগের জন্য কোনও বিশেষ সিনট্যাক্স নেই এবং তাই আমাদের টাইপ ল্যাম্বডাস নামক মনট্রোটি অবলম্বন করতে হবে। (আপনার উদাহরণে যা আছে।) তাদের এগুলি বলা হয় কারণ এগুলি মান স্তরে বিদ্যমান ল্যাম্বডা অভিব্যক্তির সাথে সাদৃশ্যপূর্ণ।
নিম্নলিখিত উদাহরণ সাহায্য করতে পারে:
// VALUE LEVEL
// foo has signature: (String, String) => String
scala> def foo(x: String, y: String): String = x + " " + y
foo: (x: String, y: String)String
// world wants a parameter of type String => String
scala> def world(f: String => String): String = f("world")
world: (f: String => String)String
// So we use a lambda expression that partially applies foo on one parameter
// to yield a value of type String => String
scala> world(x => foo("hello", x))
res0: String = hello world
// TYPE LEVEL
// Foo has a kind (*, *) -> *
scala> type Foo[A, B] = Map[A, B]
defined type alias Foo
// World wants a parameter of kind * -> *
scala> type World[M[_]] = M[Int]
defined type alias World
// So we use a lambda lambda that partially applies Foo on one parameter
// to yield a type of kind * -> *
scala> type X[A] = World[({ type M[A] = Foo[String, A] })#M]
defined type alias X
// Test the equality of two types. (If this compiles, it means they're equal.)
scala> implicitly[X[Int] =:= Foo[String, Int]]
res2: =:=[X[Int],Foo[String,Int]] = <function1>
সম্পাদনা:
আরও মান স্তর এবং ধরণের স্তরের সমান্তরাল।
// VALUE LEVEL
// Instead of a lambda, you can define a named function beforehand...
scala> val g: String => String = x => foo("hello", x)
g: String => String = <function1>
// ...and use it.
scala> world(g)
res3: String = hello world
// TYPE LEVEL
// Same applies at type level too.
scala> type G[A] = Foo[String, A]
defined type alias G
scala> implicitly[X =:= Foo[String, Int]]
res5: =:=[X,Foo[String,Int]] = <function1>
scala> type T = World[G]
defined type alias T
scala> implicitly[T =:= Foo[String, Int]]
res6: =:=[T,Foo[String,Int]] = <function1>
আপনি যে ক্ষেত্রে উপস্থাপন করেছেন সে ক্ষেত্রে, টাইপ প্যারামিটারটি R
স্থানীয়ভাবে কাজ করতে পারে Tuple2Pure
এবং তাই আপনি কেবল সংজ্ঞা দিতে পারবেন না type PartialTuple2[A] = Tuple2[R, A]
, কারণ এমন কোনও স্থান নেই যেখানে আপনি এই প্রতিশব্দটি রাখতে পারেন।
এই জাতীয় কেস মোকাবেলার জন্য, আমি নিম্নলিখিত কৌশলগুলি ব্যবহার করি যা টাইপ সদস্যদের ব্যবহার করে। (আশা করি উদাহরণটি স্ব-ব্যাখ্যামূলক)
scala> type Partial2[F[_, _], A] = {
| type Get[B] = F[A, B]
| }
defined type alias Partial2
scala> implicit def Tuple2Pure[R]: Pure[Partial2[Tuple2, R]#Get] = sys.error("")
Tuple2Pure: [R]=> Pure[[B](R, B)]