স্কালায় কারি করার দুটি উপায়; প্রত্যেকের জন্য ব্যবহারের ক্ষেত্রে কী?


83

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

def add(a:Int)(b:Int) = {a + b}
// Works
add(5)(6)
// Doesn't compile
val f = add(5)
// Works
val f = add(5)_
f(10) // yields 15

def add2(a:Int) = { b:Int => a + b }
// Works
add2(5)(6)
// Also works
val f = add2(5)
f(10) // Yields 15
// Doesn't compile
val f = add2(5)_

স্টাইল গাইডটি ভুলভাবে বোঝায় যে এগুলি একই, যখন তারা স্পষ্ট নয়। গাইডটি তৈরি ত্রিযুক্ত ফাংশনগুলি সম্পর্কে একটি বিন্দু তৈরি করার চেষ্টা করছে এবং দ্বিতীয় রূপটি "বাই-দ্য বুক" কারিরিংয়ের না হলেও এটি এখনও প্রথম ফর্মের সাথে খুব মিল (যদিও তাত্পর্যপূর্ণভাবে ব্যবহার করা সহজ কারণ আপনার প্রয়োজন নেই _)

যারা এই ফর্মগুলি ব্যবহার করেন তাদের কাছ থেকে, কখন অন্য ফর্মটি ব্যবহার করার বিষয়ে theক্যমত্য?

উত্তর:


137

একাধিক পরামিতি তালিকা পদ্ধতি

প্রকার অনুমানের জন্য

একাধিক প্যারামিটার বিভাগ সহ পদ্ধতিগুলি স্থানীয় ধরণের অনুমিতিতে সহায়তা করতে ব্যবহৃত হতে পারে, প্রথম বিভাগে পরামিতি ব্যবহার করে টাইপ আর্গুমেন্টগুলি অনুমান করা যায় যা পরবর্তী বিভাগে একটি আর্গুমেন্টের জন্য একটি প্রত্যাশিত প্রকার সরবরাহ করবে। foldLeftস্ট্যান্ডার্ড লাইব্রেরিতে এটির প্রচলিত উদাহরণ।

def foldLeft[B](z: B)(op: (B, A) => B): B

List("").foldLeft(0)(_ + _.length)

এটি যদি এই হিসাবে লিখিত হয়:

def foldLeft[B](z: B, op: (B, A) => B): B

একজনকে আরও সুস্পষ্ট প্রকারের সরবরাহ করতে হবে:

List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)

সাবলীল এপিআই এর জন্য

একাধিক পরামিতি বিভাগের পদ্ধতিগুলির জন্য আরেকটি ব্যবহার হ'ল একটি ভাষা তৈরির মতো দেখতে এমন একটি API তৈরি করা। কলার বন্ধনীগুলির পরিবর্তে ব্রেস ব্যবহার করতে পারে।

def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)

loop(2) {
   println("hello!")
}

এন আর্গুমেন্টের প্রয়োগ এম প্যারামিটার বিভাগগুলির সাথে পদ্ধতিতে তালিকাবদ্ধ করে, যেখানে এন <এম, _একটি প্রত্যাশিত প্রকারের সাথে একটি বা স্পষ্টতই স্পষ্টভাবে কোনও ফাংশনে রূপান্তরিত হতে পারে FunctionN[..]। এটি একটি সুরক্ষা বৈশিষ্ট্য, একটি ব্যাকগ্রাউন্ডের জন্য স্কালা রেফারেন্সগুলিতে স্কালার ২.০ এর পরিবর্তনের নোটগুলি দেখুন।

ত্রিযুক্ত ফাংশন

ত্রিযুক্ত ফাংশন (বা সহজভাবে, ফাংশনগুলি ফিরিয়ে দেয়) আরও সহজে এন যুক্তির তালিকায় প্রয়োগ করা হয়।

val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)

এই সামান্য সুবিধাটি কখনও কখনও সার্থক হয়। নোট করুন যে ফাংশনগুলি যদিও প্যারামেট্রিক টাইপ করা যায় না, তাই কিছু ক্ষেত্রে একটি পদ্ধতি প্রয়োজন।

আপনার দ্বিতীয় উদাহরণটি একটি সংকর: একটি প্যারামিটার বিভাগ পদ্ধতি যা কোনও ফাংশন দেয় returns

মাল্টি স্টেজ গণনা

আর কোথায় ত্রিযুক্ত ফাংশন দরকারী? এখানে একটি নিদর্শন যা সর্বদা উঠে আসে:

def v(t: Double, k: Double): Double = {
   // expensive computation based only on t
   val ft = f(t)

   g(ft, k)
}

v(1, 1); v(1, 2);

আমরা কীভাবে ফলাফল ভাগ করতে পারি f(t)? একটি সাধারণ সমাধান হ'ল এর একটি ভেক্টরাইজড সংস্করণ সরবরাহ করা v:

def v(t: Double, ks: Seq[Double]: Seq[Double] = {
   val ft = f(t)
   ks map {k => g(ft, k)}
}

কুৎসিত! আমরা সম্পর্কিত না হওয়া উদ্বেগগুলিতে জড়িয়ে পড়েছি - এর g(f(t), k)ক্রম অনুসারে গণনা এবং ম্যাপিং ks

val v = { (t: Double) =>
   val ft = f(t)
   (k: Double) => g(ft, k)       
}
val t = 1
val ks = Seq(1, 2)
val vs = ks map (v(t))

আমরা এমন একটি পদ্ধতিও ব্যবহার করতে পারি যা কোনও ফাংশন ফিরিয়ে দেয়। এক্ষেত্রে এটি কিছুটা বেশি পঠনযোগ্য:

def v(t:Double): Double => Double = {
   val ft = f(t)
   (k: Double) => g(ft, k)       
}

তবে যদি আমরা একাধিক প্যারামিটার বিভাগগুলির সাথে কোনও পদ্ধতিতে একই চেষ্টা করি তবে আমরা আটকে যাই:

def v(t: Double)(k: Double): Double = {
                ^
                `-- Can't insert computation here!
}

4
দুর্দান্ত উত্তর; আমার যদি কেবল একটির চেয়েও বেশি কিছু থাকে wish আমি হজম করব এবং স্টাইল গাইডটিতে আবেদন করব; যদি আমি সফলভাবে থেকে যাই তবে এটিই নির্বাচিত উত্তর ...
davetron5000

4
আপনি আপনার লুপের উদাহরণটি এখানে সংশোধন করতে চাইতে পারেন:def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)
ওমর ভ্যান ক্লাইটেন

এটি সংকলন করে না:val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
নীলস্কেপ

"এন আর্গুমেন্টের প্রয়োগ এম প্যারামিটার বিভাগগুলির সাথে পদ্ধতিতে তালিকাবদ্ধ করে, যেখানে এন <এম, একটি প্রত্যাশিত ধরণের ফাংশন এন [..] দ্বারা স্পষ্টভাবে একটি _, বা স্পষ্টভাবে কোনও ফাংশনে রূপান্তরিত হতে পারে।" <br/> এটি ফাংশনএক্স হওয়া উচিত নয় [..], যেখানে এক্স = এমএন?
স্ট্যাকওভার ফ্লাওয়ার

"এটি সংকলন করে না: Val f: (a: int) => (b: int) => (c: int) = a + b + c" আমার মনে হয় না "f: (a: int) = > (বি: ইনট) => (সি: ইন্ট) "সঠিক বাক্য গঠন। সম্ভবত retronym এর অর্থ "f: int => int => int => Int"। কারণ => সঠিক সংঘবদ্ধ, এটি আসলে "এফ: ইনট => (ইনট => (ইনট => ইনট))"। সুতরাং চ (1) (2) প্রকারের প্রকার = ইনট (এটি চ এর অভ্যন্তরীণ সর্বাধিক বিট)
স্ট্যাকওভারফ্লাওয়ার

16

আপনি কেবল কার্যাবলী কারি করতে পারেন, পদ্ধতি নয়। addএকটি পদ্ধতি, যাতে আপনার কোনও _ক্রিয়ায় এটির রূপান্তর জোর করা দরকার । add2একটি ফাংশন প্রদান করে, সুতরাং এটি _কেবল অপ্রয়োজনীয় নয় তবে এখানে কোনও অর্থবোধ করে না।

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


এটি অর্থবোধ করে, তাই আপনি ফর্মটি ডিফ অ্যাড (ক: ইনট) (বি: ইন্ট) কি বলবেন? সেই ডিফ এবং ডিএফ অ্যাডের মধ্যে পার্থক্য বর্ণনা করে এমন শব্দ / বাক্যটি কী (a: Int, b: int)?
davetron5000

@ ডেভেট্রন ৫০০০ প্রথমটি হ'ল একাধিক প্যারামিটার তালিকার একটি পদ্ধতি, দ্বিতীয়টি একটি প্যারামিটার তালিকার একটি পদ্ধতি।
জেস্পার

5

আমি মনে করি এটি পার্থক্যগুলি উপলব্ধি করতে সহায়তা করে যদি আমি আপনার সাথে যোগ করি তবে def add(a: Int)(b: Int): Intকেবল দুটি পরামিতি সহ একটি পদ্ধতি সংজ্ঞায়িত করা হয়, কেবলমাত্র সেই দুটি পরামিতি দুটি প্যারামিটার তালিকায় বিভক্ত করা হয়েছে (অন্যান্য মন্তব্যে এর পরিণতি দেখুন)। প্রকৃতপক্ষে, সেই পদ্ধতিটি int add(int a, int a)জাভা (স্কালার নয়!) যতটা দূরে। আপনি যখন লিখবেন add(5)_, এটি কেবল একটি ফাংশন আক্ষরিক, এর একটি সংক্ষিপ্ত রূপ { b: Int => add(1)(b) }। অন্যদিকে, আপনার সাথে add2(a: Int) = { b: Int => a + b }এমন একটি পদ্ধতি নির্ধারণ করুন যার কেবলমাত্র একটি প্যারামিটার রয়েছে, এবং জাভার জন্য এটি হবে scala.Function add2(int a)। আপনি যখন add2(1)স্কেলে লিখেন এটি কেবল একটি সরল পদ্ধতি কল (কোনও ফাংশন আক্ষরিক বিপরীতে)।

এছাড়াও যদি আপনি অবিলম্বে সমস্ত প্যারামিটার সরবরাহ করেন তবে তার addচেয়ে কম ওভারহেড (সম্ভাব্য) কম রয়েছে তা নোট করুন add2। যেমনটি add(5)(6)কেবল add(5, 6)JVM স্তরে অনুবাদ করে , কোনও Functionবস্তু তৈরি হয় না। অন্যদিকে, add2(5)(6)প্রথমে সংযুক্ত একটি Functionবস্তু তৈরি করবে 5এবং তারপরে কল apply(6)করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.