স্কেল ২.৮-এ <: <, <% <, এবং =: = এর অর্থ কী এবং সেগুলি নথিভুক্ত কোথায়?


201

আমি প্রিডিফের জন্য এপিআই ডক্সে দেখতে পাচ্ছি যে তারা জেনেরিক ফাংশনের ধরণের (থেকে) => থেকে সাবক্লাস, তবে এগুলি কেবলমাত্র বলে। উম, কি? হতে পারে কোথাও ডকুমেন্টেশন রয়েছে, তবে অনুসন্ধান ইঞ্জিনগুলি "<: <" এর মতো "নাম" খুব ভালভাবে পরিচালনা করে না, তাই আমি এটি সন্ধান করতে সক্ষম হইনি।

ফলো-আপ প্রশ্ন: আমি কখন এই মজার প্রতীক / ক্লাস ব্যবহার করব এবং কেন?


6
এখানে একটি সম্পর্কিত প্রশ্ন যা আংশিকভাবে অন্তত আপনার প্রশ্নের উত্তর দিতে পারে stackoverflow.com/questions/2603003/operator-in-scala
Yardena

13
প্রতীকহাউন্ড ডটকমটি আপনার কোড অনুসন্ধানের বন্ধু :)
রন

হাস্কেলের typeclassএস কি এই অপারেটরদের কাজ সম্পাদন করে? উদাহরণ: compare :: Ord a => a -> a -> Ordering? আমি এই স্কাল ধারণাটি এর হাস্কেলের পাল্টা অংশের সাথে সম্মানের সাথে বোঝার চেষ্টা করছি।
কেভিন মেরেডিথ

উত্তর:


217

এগুলিকে সাধারণীকরণের ধরণের সীমাবদ্ধতা বলা হয় । তারা আপনাকে টাইপ-প্যারামিটারাইজড ক্লাস বা বৈশিষ্ট্য থেকে শুরু করে এর ধরণের কোনও একটি পরামিতি বাধা দেয় । এখানে একটি উদাহরণ:

case class Foo[A](a:A) { // 'A' can be substituted with any type
    // getStringLength can only be used if this is a Foo[String]
    def getStringLength(implicit evidence: A =:= String) = a.length
}

অন্তর্নিহিত যুক্তি evidenceসংকলক দ্বারা সরবরাহ করা হয়, if Aহয় String। আপনি একটি যেমন মনে করতে পারেন প্রমাণ যে Aহয় String--দী যুক্তি নিজেই গুরুত্বপূর্ণ নয়, শুধুমাত্র বুদ্ধিমান যে এটি বিদ্যমান। [সম্পাদনা করুন: ভাল, প্রযুক্তিগতভাবে এটি আসলে গুরুত্বপূর্ণ কারণ এটি থেকে অন্তর্নিহিত রূপান্তরকে উপস্থাপন Aকরে String, যা আপনাকে কল করতে a.lengthএবং আপনার কাছে সংকলক চিৎকার না করার অনুমতি দেয় ]

এখন আমি এটি এর মতো ব্যবহার করতে পারি:

scala> Foo("blah").getStringLength
res6: Int = 4

তবে যদি আমি এটি Fooব্যতীত অন্য কোনও কিছু যুক্ত করে ব্যবহার করার চেষ্টা করেছি String:

scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]

আপনি সেই ত্রুটিটি পড়তে পারেন "" এমন প্রমাণের সন্ধান পেল না যে অন্তঃ == স্ট্রিং "... এটি যেমন হওয়া উচিত তেমন! সাধারণভাবে যা প্রয়োজন তার চেয়ে ধরণের আরও বিধিনিষেধgetStringLength আরোপ করছে ; যথা, আপনি শুধুমাত্র ডাকা যাবে একটি উপর । এই সীমাবদ্ধতা সংকলন সময়ে প্রয়োগ করা হয়, যা দুর্দান্ত!AFoogetStringLengthFoo[String]

<:<এবং <%<একইভাবে কাজ করুন, তবে কিছুটা ভিন্নতা সহ:

  • A =:= B মানে A অবশ্যই হ'ল বি
  • A <:< Bএর অর্থ A অবশ্যই B এর একটি উপপ্রকার হতে হবে ( সাধারণ ধরণের সীমাবদ্ধতার সাথে সমান <:)
  • A <%< Bএর অর্থ A অবশ্যই বি হিসাবে দেখা যাবে , সম্ভবত অন্তর্নিহিত রূপান্তরের মাধ্যমে (সাধারণ ধরণের সীমাবদ্ধতার সাথে সমান <%)

@ রেট্রোনিমের এই স্নিপেটটি এই ধরণের জিনিস কীভাবে সম্পন্ন হত এবং সাধারণ ধরণের সীমাবদ্ধতাগুলি কীভাবে এখন এটি আরও সহজ করে তোলে তার একটি ভাল ব্যাখ্যা।

অভিযোজ্য বস্তু

আপনার ফলো-আপ প্রশ্নের উত্তর দেওয়ার জন্য, স্বীকারোক্তিপূর্ণ যে উদাহরণটি আমি দিয়েছি তা বেশিরভাগ ক্ষেত্রেই কার্যকর এবং কার্যকরভাবে নয়। তবে কোনও List.sumIntsপদ্ধতির মতো কিছু সংজ্ঞায়িত করতে এটি ব্যবহার করার বিষয়টি কল্পনা করুন , যা পূর্ণসংখ্যার একটি তালিকা যুক্ত করে। আপনি এই পদ্ধতিটি কোনও পুরানোকেই অনুরোধ করার অনুমতি দিতে চান না List, কেবল একটি List[Int]। তবে Listটাইপ কনস্ট্রাক্টর এতটা বাধা দেওয়া যায় না; আপনি এখনও স্ট্রিং, ফু, বার এবং হোয়াটসনের তালিকা পেতে সক্ষম হতে চান। সুতরাং একটি সাধারণ ধরণের সীমাবদ্ধতা রেখে sumInts, আপনি নিশ্চিত করতে পারেন যে কেবলমাত্র সেই পদ্ধতির একটি অতিরিক্ত বাধা রয়েছে যা এটি কেবল একটিতে ব্যবহার করা যেতে পারে List[Int]। মূলত আপনি নির্দিষ্ট ধরণের তালিকার জন্য বিশেষ-ক্ষেত্রে কোডটি লিখছেন।


3
ঠিক আছে, ঠিক আছে, কিন্তু একই নামগুলির সাথে পদ্ধতি রয়েছে Manifestযা আপনি উল্লেখ করেন নি।
ড্যানিয়েল সি সোব্রাল

3
উপর পদ্ধতি Manifestহয় <:<এবং >:>শুধুমাত্র ... যেহেতু ওপি উল্লিখিত সাধারণ টাইপ সীমাবদ্ধতার ঠিক 3 জাতের, আমি কি তিনি আগ্রহী ছিলেন অভিমানী করছি।
টম Crockett,

12
@IttayD: এটা প্রশংসনীয় চালাক আছে ... class =:=[From, To] extends From => To, যার মানে প্রকারের একটি অন্তর্নিহিত মূল্য From =:= Toআসলে একটি অন্তর্নিহিত হয় রূপান্তর থেকে Fromথেকে To। সুতরাং প্রকারের একটি অন্তর্নিহিত পরামিতি গ্রহণ করে A =:= Stringআপনি বলছেন যে Aঅন্তর্নিহিত রূপান্তরিত হতে পারে String। আপনি যদি অর্ডার পরিবর্তন করে এবং অন্তর্নিহিত যুক্তিটি প্রকারভেদে তৈরি করেন তবে String =:= Aএটি কার্যকর হবে না, কারণ এটি থেকে অন্তর্ভুক্ত রূপান্তর Stringহবে A
টম ক্রকেট

25
এই তিনটি চরিত্রের চিহ্নগুলির কি নাম আছে? স্কালার প্রতীক স্যুপের সাথে আমার সমস্যা হ'ল তারা মৌখিকভাবে কথা বলা শক্ত এবং তাদের ব্যবহারের আলোচনা এবং উদাহরণ খুঁজে পেতে গুগল বা অন্য কোনও সার্চ ইঞ্জিন ব্যবহার করা কার্যত অসম্ভব।
গিগাস্ট্রন

4
@ আন্ড্রেয়া নাপ, প্রকারগুলি ঠিক সমান হলে এটি কাজ করবে। নোট করুন যে আমি বলেছিলাম যে From =:= Toসুযোগের প্রকারের অন্তর্নিহিত মানটি বোঝায় যে আপনার একটি অন্তর্নিহিত রূপান্তর আছে From => To, তবে জড়িত হওয়াটি পিছনের দিকে চলে না; অন্তর্নিহিত রূপান্তরটি A => Bবোঝায় না যে আপনার উদাহরণ রয়েছে A =:= B=:=এটি একটি সিলযুক্ত বিমূর্ত শ্রেণীর সংজ্ঞা দেওয়া হয়েছে scala.Predef, এবং এর কেবলমাত্র প্রকাশ্যে উদ্ভাসিত উদাহরণ রয়েছে, যা অন্তর্নিহিত এবং প্রকারের A =:= A। সুতরাং আপনি গ্যারান্টিযুক্ত যে প্রকারের একটি অন্তর্নির্মিত মান A =:= Bসত্য Aএবং Bসমান হিসাবে সাক্ষ্য দেয় ।
টম ক্রকেট

55

একটি সম্পূর্ণ উত্তর নয় (অন্যরা ইতিমধ্যে এটির উত্তর দিয়েছেন), আমি কেবল নিম্নলিখিতটি নোট করতে চেয়েছিলাম, যা সম্ভবত সিনট্যাক্সটি আরও ভালভাবে বুঝতে সহায়তা করে: পেলোটমের উদাহরণ হিসাবে যেমন আপনি সাধারণত এই "অপারেটরগুলি" ব্যবহার করেন:

def getStringLength(implicit evidence: A =:= String)

প্রকার অপারেটরদের জন্য স্কালার বিকল্প ইনফিক্স সিনট্যাক্স ব্যবহার করে

সুতরাং, A =:= Stringহিসাবে একই =:=[A, String](এবং =:=শুধু একটি বর্গ বা বৈশিষ্ট্য একটি অভিনব সুদর্শন নামের সঙ্গে যায়)। নোট করুন যে এই বাক্য গঠনটি "নিয়মিত" ক্লাসগুলির সাথেও কাজ করে, উদাহরণস্বরূপ আপনি লিখতে পারেন:

val a: Tuple2[Int, String] = (1, "one")

এটার মত:

val a: Int Tuple2 String = (1, "one")

এটি পদ্ধতি কলগুলির জন্য দুটি সিনট্যাক্সের সাথে .এবং ()অপারেটর সিনট্যাক্সের সাথে "সাধারণ" এর মতো ।


2
উজ্জীবিত হওয়া দরকার কারণ makes use of Scala's alternative infix syntax for type operators.সম্পূর্ণরূপে এই ব্যাখ্যাটি অনুপস্থিত যা ছাড়া পুরো জিনিসটি বোঝায় না
ওভিদিউ দোলহা

39

এই নির্মাণগুলি কী তা বোঝার জন্য অন্যান্য উত্তরগুলি পড়ুন। আপনার যখন এটি ব্যবহার করা উচিত তখন এখানে । যখন আপনি কেবল নির্দিষ্ট ধরণের জন্য কোনও পদ্ধতি সীমাবদ্ধ করতে চান আপনি সেগুলি ব্যবহার করেন।

এখানে একটি উদাহরণ। ধরুন আপনি এই জাতীয় একটি সংযুক্ত জুটি সংজ্ঞায়িত করতে চান:

class Pair[T](val first: T, val second: T)

এখন আপনি smallerএই পদ্ধতিটি যুক্ত করতে চান :

def smaller = if (first < second) first else second

যদি Tকেবল আদেশ হয় তবে তা কাজ করে । আপনি পুরো শ্রেণিকে সীমাবদ্ধ করতে পারেন:

class Pair[T <: Ordered[T]](val first: T, val second: T)

তবে এটি লজ্জাজনক বলে মনে হচ্ছে - যখন Tআদেশ না দেওয়া হয় তখন শ্রেণীর জন্য ব্যবহারগুলি হতে পারে । একধরণের বাধা সহ, আপনি এখনও smallerপদ্ধতিটি সংজ্ঞায়িত করতে পারেন :

def smaller(implicit ev: T <:< Ordered[T]) = if (first < second) first else second

এটা তোলে instantiate করার ঠিক আছে, বলে, একটি Pair[File], যতদিন না পর্যন্ত আপনি কল না যেমন smaller এটা।

ক্ষেত্রে Option, বাস্তবায়নকারীরা একটি orNullপদ্ধতি চেয়েছিলেন , যদিও এটি বোঝায় না Option[Int]। একটি টাইপ সীমাবদ্ধতা ব্যবহার করে, সব ঠিক আছে। আপনি ব্যবহার করতে পারেন orNullএকটি অন Option[String], এবং আপনি একটি গঠন করতে পারেন Option[Int]এবং ব্যবহার এটা যতদিন আপনি কল না orNullএটা। যদি আপনি চেষ্টা করেন Some(42).orNull, আপনি আকর্ষণীয় বার্তা পাবেন

 error: Cannot prove that Null <:< Int

2
আমি বুঝতে পেরেছি যে এই উত্তরটির বহু বছর পরে, তবে আমি ব্যবহারের ক্ষেত্রে খুঁজছি <:<, এবং আমি মনে করি যে Orderedউদাহরণটি আর তেমন জোরালো নয় কারণ আপনি এখন বৈশিষ্ট্যের Orderingচেয়ে টাইপক্লাসটি ব্যবহার করবেন Ordered। ভালো কিছু: def smaller(implicit ord: Ordering[T]) = if (ord.lt(first, second)) first else second
ইব্রুচেজ

1
@ ইব্রুচেজ: একটি ব্যবহারের ক্ষেত্রটি ইউনিয়ন বিহীন মডেলগুলিতে এনকোডিংয়ের জন্য, মাইলস্যাবিন

17

এটি কোথায় ব্যবহৃত হচ্ছে তার উপর নির্ভর করে। প্রায়শই, অন্তর্ভুক্ত পরামিতিগুলির ধরণের ঘোষণার সময় ব্যবহৃত হয়, তারা ক্লাস হয়। এগুলি বিরল দৃষ্টান্তগুলিতেও বস্তু হতে পারে। শেষ অবধি, তারা Manifestবস্তুতে অপারেটর হতে পারে । scala.Predefপ্রথম দুটি ক্ষেত্রে এগুলি ভিতরে সংজ্ঞায়িত করা হয় , যদিও বিশেষভাবে নথিভুক্ত হয়নি।

এগুলি বোঝানো হয় ক্লাসগুলির মধ্যে সম্পর্কের পরীক্ষা করার একটি উপায় সরবরাহ করার জন্য, ঠিক যেমনটি করা হয় <:এবং <%ঠিক সেই পরিস্থিতিতে যখন পরে ব্যবহার করা যায় না।

"আমি কখন তাদের ব্যবহার করব?" এই প্রশ্নের উত্তর হিসাবে, আপনি যদি না জানেন তবে আপনার উত্তর হওয়া উচিত নয়। :-) সম্পাদনা করুন : ঠিক আছে, ঠিক আছে, এখানে গ্রন্থাগার থেকে কিছু উদাহরণ দেওয়া আছে। চালু Either, আপনার আছে:

/**
  * Joins an <code>Either</code> through <code>Right</code>.
  */
 def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match {
   case Left(a)  => Left(a)
   case Right(b) => b
 }

 /**
  * Joins an <code>Either</code> through <code>Left</code>.
  */
 def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match {
   case Left(a)  => a
   case Right(b) => Right(b)
 }

চালু Option, আপনার আছে:

def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

সংগ্রহগুলিতে আপনি আরও কিছু উদাহরণ পাবেন।


এর মধ্যে :-)আর একটি? এবং আমি সম্মত হব যে আপনার উত্তর "আমি কখন তাদের ব্যবহার করব?" একটি মহান অনেক জিনিস প্রযোজ্য।
মাইক মিলার

"তারা ক্লাসগুলির মধ্যে সম্পর্কের পরীক্ষা করার একটি উপায় সরবরাহ করার জন্য বোঝানো হয়েছে" <- খুব সাধারণভাবে সহায়ক হতে পারে না
জেফ

3
"আমি কখন তাদের ব্যবহার করব?" "এই প্রশ্নের উত্তরটি আপনার হওয়া উচিত নয়, যদি না আপনি জানেন যে আপনার উচিত।" <- এজন্য আমি জিজ্ঞাসা করছি আমি নিজের জন্য এই দৃ determination় সংকল্প করতে সক্ষম হতে চাই।
জেফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.