অন্তর্নির্মিত রূপান্তর বনাম প্রকারের শ্রেণি


94

স্কালায়, আমরা বিদ্যমান বা নতুন ধরণের পুনঃনির্মাণের জন্য কমপক্ষে দুটি পদ্ধতি ব্যবহার করতে পারি। ধরা যাক আমরা প্রকাশ করতে চাই যে একটি ব্যবহার করে কিছু পরিমানযোগ্য হতে পারে Int। আমরা নিম্নলিখিত বৈশিষ্ট্য সংজ্ঞায়িত করতে পারি।

অন্তর্নিহিত রূপান্তর

trait Quantifiable{ def quantify: Int }

এবং তারপরে আমরা স্ট্রিংস এবং লিস্টগুলির পরিমাণ নির্ধারণের জন্য অন্তর্নিহিত রূপান্তরগুলি ব্যবহার করতে পারি।

implicit def string2quant(s: String) = new Quantifiable{ 
  def quantify = s.size 
}
implicit def list2quantifiable[A](l: List[A]) = new Quantifiable{ 
  val quantify = l.size 
}

এগুলি আমদানির পরে, আমরা quantifyস্ট্রিং এবং তালিকাগুলিতে পদ্ধতিটি কল করতে পারি । নোট করুন যে পরিমাণের পরিমাণটি তার দৈর্ঘ্য সংরক্ষণ করে তাই এটি পরবর্তী কলগুলিতে তালিকার ব্যয়বহুল ট্র্যাভারসাল এড়িয়ে চলে quantify

ক্লাস টাইপ করুন

একটি বিকল্প হ'ল "সাক্ষী" সংজ্ঞায়িত করা Quantified[A]যা উল্লেখ করে যে, কিছু প্রকারের Aপরিমাণ নির্ধারণ করা যেতে পারে।

trait Quantified[A] { def quantify(a: A): Int }

আমরা তখন জন্য এই ধরনের ক্লাসের দৃষ্টান্ত প্রদান Stringএবং Listকোথাও।

implicit val stringQuantifiable = new Quantified[String] {
  def quantify(s: String) = s.size 
}

এবং যদি আমরা তারপরে যুক্তিগুলির পরিমাণ নির্ধারণের জন্য একটি পদ্ধতি লিখি তবে আমরা লিখি:

def sumQuantities[A](as: List[A])(implicit ev: Quantified[A]) = 
  as.map(ev.quantify).sum

বা প্রসঙ্গের বাউন্ড সিনট্যাক্স ব্যবহার করে:

def sumQuantities[A: Quantified](as: List[A]) = 
  as.map(implicitly[Quantified[A]].quantify).sum

তবে কখন কোন পদ্ধতিটি ব্যবহার করবেন?

এখন প্রশ্ন আসে। এই দুটি ধারণার মধ্যে আমি কীভাবে সিদ্ধান্ত নিতে পারি?

আমি এখন পর্যন্ত কি লক্ষ্য করেছি।

টাইপ ক্লাস

  • টাইপ ক্লাসগুলি সুন্দর প্রসঙ্গের বাউন্ড সিনট্যাক্সের অনুমতি দেয়
  • প্রকারের ক্লাসগুলির সাথে আমি প্রতিটি ব্যবহারে একটি নতুন র‌্যাপার বস্তু তৈরি করি না
  • প্রসঙ্গের বাউন্ড সিনট্যাক্সটি আর কাজ করে না যদি ধরণের শ্রেণিতে একাধিক ধরণের পরামিতি থাকে; কল্পনা করুন যে আমি জিনিসগুলি কেবল পূর্ণসংখ্যার সাথেই নয় কিছু সাধারণ ধরণের মানগুলির সাথে মানিয়ে তুলতে চাই T। আমি একটি টাইপ ক্লাস তৈরি করতে চাইQuantified[A,T]

অন্তর্নিহিত রূপান্তর

  • যেহেতু আমি একটি নতুন অবজেক্ট তৈরি করেছি, আমি সেখানে মানগুলি ক্যাশে করতে পারি বা আরও ভাল উপস্থাপনা গণনা করতে পারি; তবে আমি কি এড়ানো উচিত, যেহেতু এটি বেশ কয়েকবার ঘটতে পারে এবং একটি স্পষ্ট রূপান্তর সম্ভবত একবারেই ডাকা হত?

আমি উত্তর থেকে কি আশা করি

একটি (বা একাধিক) ব্যবহারের কেস (গুলি) উপস্থাপন করুন যেখানে উভয় ধারণার মধ্যে পার্থক্য রয়েছে এবং ব্যাখ্যা করুন যে আমি কেন অন্যটির চেয়ে বেশি পছন্দ করি। দুটি ধারণার মর্ম এবং একে অপরের সাথে তাদের সম্পর্কের ব্যাখ্যাও খুব সুন্দর হবে, এমনকি উদাহরণ ছাড়াই।


প্রকার শ্রেণি পয়েন্টগুলিতে কিছু বিভ্রান্তি রয়েছে যেখানে আপনি "দেখুন বাউন্ড" উল্লেখ করেছেন, যদিও ধরণের শ্রেণিগুলি প্রসঙ্গের সীমা ব্যবহার করে।
ড্যানিয়েল সি সোব্রাল

4
+1 দুর্দান্ত প্রশ্ন; আমি এই সম্পর্কে একটি সম্পূর্ণ উত্তর খুব আগ্রহী।
ড্যান বার্টন

@ ড্যানিয়েল আপনাকে ধন্যবাদ আমি সবসময় এই ভুল পেতে।
ziggystar

4
আপনি এক জায়গায় ভুল করছেন: আপনার দ্বিতীয় অন্তর্নিহিত রূপান্তর উদাহরণে আপনি সংরক্ষণ sizeএকটি মান একটি তালিকার বলবো যে, এটা পরিমাণ নির্ণয় করার পরবর্তী কল তালিকার ব্যয়বহুল ট্র্যাভেরসাল এড়াতে, কিন্তু আপনার প্রতি কলে আলোড়ন সৃষ্টি পরার সমস্ত আবার এইভাবে পুনর্বহাল এবং সম্পত্তি পুনরায় গণনা । আমি যা বলছি তা হ'ল প্রকৃত রূপান্তর সহ ফলাফলগুলি ক্যাশে করার কোনও উপায় নেই। quantifylist2quantifiableQuantifiablequantify
নিকিতা ভলকভ

@ নিকিতাভোলকভ আপনার পর্যবেক্ষণটি সঠিক। এবং আমি আমার প্রশ্নের দ্বিতীয় থেকে শেষ অনুচ্ছেদে এটি যুক্ত করি। ক্যাচিং কাজ করে, যখন রূপান্তরিত বস্তুটি একটি রূপান্তরকারী পদ্ধতি কল করার পরে দীর্ঘ সময়ের জন্য ব্যবহৃত হয় (এবং সম্ভবত এটি রূপান্তরিত আকারে প্রেরণ করা হয়)। আরও গভীরতর অবস্থায় যখন টাইপ ক্লাসগুলি সম্ভবত রূপান্তরিত অবজেক্টের সাথে শৃঙ্খলিত হবে।
ziggystar

উত্তর:


42

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

def foo[T: TypeClass](t: T) = ...

একটি স্থানীয় টাইপ শ্রেণীর জন্য এর স্থানীয় পরিবেশ অনুসন্ধান করার ক্ষমতা রয়েছে। যাইহোক, আমি যে কোনও সময়ে দুটি পদ্ধতির একটি দ্বারা ডিফল্ট আচরণকে ওভাররাইড করতে পারি:

  1. স্কোপের শর্ট-সার্কিটের অন্তর্নিহিত চেহারাতে অন্তর্নিহিত ধরণের শ্রেণীর উদাহরণ তৈরি / আমদানি করা
  2. সরাসরি একটি টাইপ ক্লাস পাস

এখানে একটি উদাহরণ:

def myMethod(): Unit = {
   // overrides default implicit for Int
   implicit object MyIntFoo extends Foo[Int] { ... }
   foo(5)
   foo(6) // These all use my overridden type class
   foo(7)(new Foo[Int] { ... }) // This one needs a different configuration
}

এটি টাইপ ক্লাসগুলি অসীম আরও নমনীয় করে তোলে। আরেকটি বিষয় হ'ল ধরণের শ্রেণি / বৈশিষ্ট্যগুলি আরও ভালভাবে অন্তর্নিহিত অনুসন্ধানকে সমর্থন করে ।

আপনার প্রথম উদাহরণে, আপনি যদি অন্তর্নির্মিত দৃশ্য ব্যবহার করেন তবে সংকলক এর জন্য একটি অন্তর্নিহিত অনুসন্ধান করবে:

Function1[Int, ?]

যা Function1এর সহযোগী বস্তু এবং সহকর্মী অবজেক্টের দিকে নজর দেবে Int

অন্তর্নিহিত অনুসন্ধানে কোথাও নেইQuantifiable তা লক্ষ্য করুন । এর অর্থ আপনাকে প্যাকেজ অবজেক্টে অন্তর্নিহিত দৃষ্টিভঙ্গি রাখতে হবে বা এটিকে স্কোপে আমদানি করতে হবে। কী চলছে তা মনে রাখা আরও কাজ।

অন্যদিকে, একটি ধরণের শ্রেণি স্পষ্ট । আপনি পদ্ধতির স্বাক্ষরে এটি কী সন্ধান করছে তা দেখুন। আপনার একটি অন্তর্নিহিত লুকও আছে

Quantifiable[Int]

যা Quantifiableএর সহযোগী অবজেক্ট এবং এর সহযোগী অবজেক্টে দেখবে Int। অর্থ যে আপনি ডিফল্ট প্রদান করতে পারেন এবং নতুন ধরণের ( MyStringশ্রেণীর মতো ) তাদের সহযোগী অবজেক্টে একটি ডিফল্ট সরবরাহ করতে পারে এবং এটি স্পষ্টভাবে অনুসন্ধান করা হবে।

সাধারণভাবে, আমি টাইপ ক্লাস ব্যবহার করি। এগুলি প্রাথমিক উদাহরণের জন্য অসীম আরও নমনীয়। আমি স্কেল র‌্যাপার এবং জাভা লাইব্রেরির মধ্যে একটি এপিআই স্তর ব্যবহার করার সময় কেবলমাত্র অন্তর্নিহিত রূপান্তরগুলিই ব্যবহার করি এবং আপনি যদি সতর্ক না হন তবে এটি 'বিপজ্জনক' হতে পারে।


20

একটি মানদণ্ড যা খেলতে আসতে পারে তা হল আপনি কীভাবে নতুন বৈশিষ্ট্যটিকে "অনুভব" করতে চান; অন্তর্নিহিত রূপান্তরগুলি ব্যবহার করে আপনি এটিকে দেখতে অন্যরকম পদ্ধতি দেখানোর মতো করে তুলতে পারেন:

"my string".newFeature

... প্রকারের ক্লাসগুলি ব্যবহার করার সময় এটি সর্বদা এটির মতো দেখায় যে আপনি কোনও বাহ্যিক ফাংশন বলছেন:

newFeature("my string")

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

trait Default[T] { def value : T }

implicit object DefaultInt extends Default[Int] {
  def value = 42
}

implicit def listsHaveDefault[T : Default] = new Default[List[T]] {
  def value = implicitly[Default[T]].value :: Nil
}

def default[T : Default] = implicitly[Default[T]].value

scala> default[List[List[Int]]]
resN: List[List[Int]] = List(List(42))

এই উদাহরণটি দেখায় যে কীভাবে ধারণাগুলি দৃ related়ভাবে সম্পর্কিত type তাদের ধরণের উদাহরণগুলি অসীমভাবে উত্পাদন করার ব্যবস্থা না থাকলে টাইপ ক্লাসগুলি প্রায় কার্যকর হবে না; implicitপদ্ধতি ব্যতীত (কোনও রূপান্তর নয়, স্বীকারোক্তিযুক্ত) ছাড়াই আমি কেবল চূড়ান্তভাবে অনেক ধরণের Defaultসম্পত্তি পেতে পারি।


@ ফিলিপ - আপনি যে কৌশলটি লিখেছিলেন সে সম্পর্কে আমি খুব আগ্রহী ... তবে এটি স্কেল 2.11.6 তে কাজ করছে না বলে মনে হচ্ছে। আমি আপনার উত্তর সম্পর্কে একটি আপডেট জিজ্ঞাসা একটি প্রশ্ন পোস্ট। আপনি যদি সহায়তা করতে পারেন তবে আগাম ধন্যবাদ: দয়া করে দেখুন: stackoverflow.com/questions/31910923/…
ক্রিস বেডফোর্ড

@ ক্রিসবেডফোর্ড আমি defaultভবিষ্যতের পাঠকদের জন্য সংজ্ঞাটি যুক্ত করেছি ।
ফিলিপ

13

কার্যকারিতা প্রয়োগের সাথে সাদৃশ্য করে দুটি কৌশলটির মধ্যে পার্থক্যটি কেবলমাত্র একটি নামী মোড়কের সাথে ভাবতে পারেন। উদাহরণ স্বরূপ:

trait Foo1[A] { def foo(a: A): Int }  // analogous to A => Int
trait Foo0    { def foo: Int }        // analogous to Int

পূর্ববর্তী A => Intএকটি উদাহরণ টাইপ একটি ফাংশন encapsulates , অন্যদিকে একটি উদাহরণ ইতিমধ্যে একটি প্রয়োগ করা হয়েছে A। আপনি নিদর্শন চালিয়ে যেতে পারেন ...

trait Foo2[A, B] { def foo(a: A, b: B): Int } // sort of like A => B => Int

এইভাবে আপনি কিছু উদাহরণের Foo1[B]আংশিক প্রয়োগের মতো ধরণের সম্পর্কে ভাবতে পারেন । এর একটি দুর্দান্ত উদাহরণ মাইলস সাবিন লিখেছিলেন "স্কালার কার্যকরী নির্ভরতা" হিসাবে ।Foo2[A, B]A

সুতরাং সত্যই আমার বক্তব্যটি নীতিগতভাবে:

  • একটি ক্লাসকে "পিম্পিং" (অন্তর্নিহিত রূপান্তরের মাধ্যমে) "শূন্যপদ আদেশ" কেস ...
  • টাইপক্লাস ঘোষণা করা "প্রথম আদেশ" কেস ...
  • ফান্ডেপস (বা ফান্ডেপের মতো কিছু) সহ বহু-পরামিতি টাইপক্লাসগুলি সাধারণ ক্ষেত্রে।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.