আমি স্কালা ফাংশনগুলি ( স্কালার আরেকটি সফরের অংশ ) পড়েছি । সেই পোস্টে তিনি বলেছিলেন:
পদ্ধতি এবং ফাংশন একই জিনিস নয়
তবে তিনি এ সম্পর্কে কিছুই ব্যাখ্যা করেননি। সে কী বলার চেষ্টা করছিল?
আমি স্কালা ফাংশনগুলি ( স্কালার আরেকটি সফরের অংশ ) পড়েছি । সেই পোস্টে তিনি বলেছিলেন:
পদ্ধতি এবং ফাংশন একই জিনিস নয়
তবে তিনি এ সম্পর্কে কিছুই ব্যাখ্যা করেননি। সে কী বলার চেষ্টা করছিল?
উত্তর:
জিম এটি তার ব্লগ পোস্টে বেশ কভার পেয়েছে তবে আমি এখানে একটি ব্রিফিং পোস্ট করছি রেফারেন্সের জন্য।
প্রথমে আসুন দেখুন স্কালা স্পেসিফিকেশন আমাদের কী বলে। অধ্যায় 3 (প্রকার) আমাদের ফাংশন প্রকারগুলি (3.2.9) এবং পদ্ধতি প্রকারগুলি (3.3.1) সম্পর্কে বলুন । অধ্যায় 4 (বেসিক ঘোষণা) মান ঘোষণা এবং সংজ্ঞা (4.1), পরিবর্তনশীল ঘোষণা এবং সংজ্ঞা (4.2) এবং কার্যকারিতা ঘোষণা এবং সংজ্ঞা (4.6) সম্পর্কে কথা বলে। অধ্যায় 6 (এক্সপ্রেশন) অজ্ঞাতনামা ফাংশন (6.23) এবং পদ্ধতি মানগুলি (6.7) সম্পর্কে কথা বলে। কৌতূহলজনকভাবে, ফাংশন মানগুলি 3.2.9 এ এক সময়ের কথা বলা হয় এবং অন্য কোথাও হয় না।
একটি ফাংশন টাইপ (মোটামুটিভাবে) ফর্মের একটি ধরণ (টি 1, ..., টিএন) => ইউ , যা FunctionN
স্ট্যান্ডার্ড লাইব্রেরির বৈশিষ্ট্যের জন্য একটি শর্টহ্যান্ড । বেনামে ফাংশন এবং পদ্ধতি মানগুলিতে ফাংশনের ধরণ রয়েছে এবং ফাংশন প্রকারগুলি মান, পরিবর্তনশীল এবং ফাংশন ঘোষণা এবং সংজ্ঞাগুলির অংশ হিসাবে ব্যবহার করা যেতে পারে। আসলে, এটি কোনও পদ্ধতির ধরণের অংশ হতে পারে।
একটি মেথড টাইপ হ'ল একটি অ-মান টাইপ । এর অর্থ কোনও পদ্ধতির ধরণের সাথে কোনও মূল্য নেই - কোনও বস্তু নেই, কোনও উদাহরণ নেই। উপরে উল্লিখিত হিসাবে, একটি পদ্ধতি মান আসলে একটি ফাংশন টাইপ আছে । একটি পদ্ধতির ধরণ হ'ল def
ঘোষণা - def
এর দেহ ব্যতীত সমস্ত কিছু ।
মান ঘোষণা এবং সংজ্ঞা এবং পরিবর্তনীয় ঘোষণা এবং সংজ্ঞা হয় val
এবং var
ঘোষণা, উভয় সহ প্রকার ও মান - যা হতে পারে, যথাক্রমে ফাংশন ধরণ এবং বেনামী কার্যাবলী বা পদ্ধতি মানগুলি । নোট করুন, জেভিএম-এ, এই (পদ্ধতির মানগুলি) জাভা যা "পদ্ধতি" বলে ডাকে তা প্রয়োগ করা হয়।
একটি কার্য ঘোষণা একটি হল def
সহ ঘোষণা, টাইপ এবং শরীর । টাইপ অংশটি হ'ল মেথডের ধরণ এবং শরীরটি একটি এক্সপ্রেশন বা একটি ব্লক । এটি জাভাতে "পদ্ধতি" বলার সাথে জেভিএম-তেও প্রয়োগ করা হয়।
অবশেষে, একটি বেনামী ফাংশন একটি একটি দৃষ্টান্ত হল ফাংশন ধরণ (অর্থাত, বৈশিষ্ট্যের একটি দৃষ্টান্তFunctionN
), এবং একটি পদ্ধতি মূল্য একই কথা! পার্থক্যটি হ'ল পদ্ধতিগুলি থেকে একটি মেথড মান তৈরি করা হয়, হয় একটি আন্ডারস্কোর পোস্টফিক্স করে ( m _
"ফাংশন ডিক্লেয়ারেশন" ( def
) এর সাথে সম্পর্কিত একটি পদ্ধতি মান m
), বা এটি -প্রসারণ নামক প্রক্রিয়া দ্বারা , যা পদ্ধতি থেকে স্বয়ংক্রিয় কাস্টের মতো is কাজ করা।
চশমাটি এটাই বলে, তাই এই বিষয়টিকে সামনে রেখে দেওয়া যাক: আমরা সেই পরিভাষাটি ব্যবহার করি না!এটি তথাকথিত "ফাংশন ডিক্লেয়ারেশন" এর মধ্যে অত্যধিক বিভ্রান্তির দিকে পরিচালিত করে , যা প্রোগ্রামের একটি অংশ (চতুর্থ অধ্যায় - মূল ঘোষণা) এবং "বেনামে ফাংশন" , যা একটি এক্সপ্রেশন এবং "ফাংশন টাইপ" , যা, ভাল একটি প্রকার - একটি বৈশিষ্ট্য।
নীচের পরিভাষা, এবং অভিজ্ঞ স্কালা প্রোগ্রামারদের দ্বারা ব্যবহৃত, স্পেসিফিকেশনের পরিভাষা থেকে একটি পরিবর্তন করে: ফাংশন ঘোষণার পরিবর্তে , আমরা পদ্ধতিটি বলি । বা এমনকি পদ্ধতি ঘোষণা। তদ্ব্যতীত, আমরা নোট করি যে মান ঘোষণাপত্র এবং পরিবর্তনশীল ঘোষণাগুলিও ব্যবহারিক উদ্দেশ্যগুলির জন্য পদ্ধতি।
সুতরাং, পরিভাষায় উপরের পরিবর্তনটি দেওয়া, এখানে পার্থক্যের একটি বাস্তব ব্যাখ্যা দেওয়া হল।
একটি ফাংশন একটি বস্তু যে এক রয়েছে FunctionX
যেমন বৈশিষ্ট্যগুলো, Function0
, Function1
, Function2
, ইত্যাদিতে সহ করা যেতে পারে PartialFunction
হিসাবে ভাল যা আসলে প্রসারিত, Function1
।
আসুন এই বৈশিষ্টগুলির মধ্যে একটির জন্য স্বাক্ষরের প্রকারটি দেখুন:
trait Function2[-T1, -T2, +R] extends AnyRef
এই বৈশিষ্ট্যের একটি বিমূর্ত পদ্ধতি রয়েছে (এটিতে কয়েকটি কংক্রিট পদ্ধতিও রয়েছে):
def apply(v1: T1, v2: T2): R
এবং এটি আমাদের সম্পর্কে যা জানার আছে তা সবই বলি। একটি ফাংশনটিতে এমন একটি apply
পদ্ধতি রয়েছে যা টি 1 , টি 2 , ..., টিএন প্রকারের N পরামিতিগুলি গ্রহণ করে এবং টাইপের কিছু দেয় R
। এটি প্রাপ্ত প্যারামিটারগুলির তুলনায় এটি বৈকল্পিক এবং ফলাফলের সহ-বৈকল্পিক।
তারতম্যটির অর্থ Function1[Seq[T], String]
হ'ল a এর একটি উপপ্রকার Function1[List[T], AnyRef]
। সাব টাইপ হওয়ার অর্থ এটি এর জায়গায় ব্যবহার করা যেতে পারে । যে কেউ কল করতে চলেছি তা সহজেই দেখতে পাবেf(List(1, 2, 3))
এবং AnyRef
পিছনে প্রত্যাশা করতে চাইলে উপরের দুটি ধরণের উভয়ই কাজ করবে।
এখন, একটি পদ্ধতি এবং একটি ফাংশনের মিল কী ? ঠিক আছে, যদি f
কোনও ফাংশন হয় এবং m
কোনও ক্ষেত্রের স্থানীয় পদ্ধতি হয় তবে উভয়কেই এটির মতো বলা যেতে পারে:
val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))
এই কলগুলি আসলে আলাদা, কারণ প্রথমটি কেবল একটি সিনট্যাকটিক চিনি। স্কালা এটিকে প্রসারিত করে:
val o1 = f.apply(List(1, 2, 3))
যা অবশ্যই অবজেক্টে একটি মেথড কল f
। ফাংশনগুলিতে এর সুবিধার জন্য অন্যান্য সিনট্যাকটিক শর্করাও রয়েছে: ফাংশন আক্ষরিক (এর মধ্যে দুটি আসলে) এবং (T1, T2) => R
স্বাক্ষরগুলি টাইপ করুন। উদাহরণ স্বরূপ:
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
case i: Int => "Int"
case d: Double => "Double"
case o => "Other"
}
একটি পদ্ধতি এবং একটি ফাংশনের মধ্যে আরেকটি মিল হ'ল প্রাক্তনটিকে সহজেই পরবর্তীকালে রূপান্তর করা যায়:
val f = m _
স্কেলা এটিকে প্রসারিত করবে , ধরে নিলে m
ধরণের (List[Int])AnyRef
ধরণটি (স্কেলা ২.7):
val f = new AnyRef with Function1[List[Int], AnyRef] {
def apply(x$1: List[Int]) = this.m(x$1)
}
স্কেলা ২.৮ এ এটি আসলে একটি ব্যবহার করে AbstractFunction1
শ্রেণীর আকার হ্রাস ক্লাস করে।
লক্ষ্য করুন যে একটি অন্য পদ্ধতিতে - কোনও ফাংশন থেকে কোনও পদ্ধতিতে রূপান্তর করতে পারে না।
পদ্ধতিগুলির তবে একটি বড় সুবিধা রয়েছে (ভাল, দুটি - তারা কিছুটা দ্রুত হতে পারে): তারা টাইপ পরামিতিগুলি গ্রহণ করতে পারে । উদাহরণস্বরূপ, উপরেরটি f
অগত্যা List
এটি প্রাপ্তির ধরণটি নির্দিষ্টভাবে নির্দিষ্ট করতে পারে ( List[Int]
উদাহরণস্বরূপ), m
এটি প্যারামিটারাইজ করতে পারে:
def m[T](l: List[T]): String = l mkString ""
আমি মনে করি এটি বেশ কিছুটা কভার করে, তবে আমি যে কোনও প্রশ্নের উত্তর দিয়ে এটি পরিপূর্ণ করতে পেরে খুশি হব।
val f = m
সংকলক দ্বারা সম্প্রসারণের উদ্ধৃতি দিয়েছিলেন যখন আপনি val f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
উল্লেখ করতে হবে যে this
অভ্যন্তরীণ apply
পদ্ধতিটি AnyRef
বস্তুকে নির্দেশ করে না , তবে সেই পদ্ধতিতে যার পদ্ধতিতে val f = m _
মূল্যায়ন করা হয় ( বাহ্যিক this
, তাই বলে) ), যেহেতু this
ক্লোজারের মাধ্যমে ধরা পড়া মানগুলির মধ্যে রয়েছে (যেমন return
নীচের দিকে নির্দেশিত হিসাবে)
একটি পদ্ধতি এবং একটি ফাংশন মধ্যে একটি বড় ব্যবহারিক পার্থক্য return
মানে কি । return
কেবল কখনও কোনও পদ্ধতি থেকে ফিরে আসে। উদাহরণ স্বরূপ:
scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
val f = () => { return "test" }
^
কোনও পদ্ধতিতে সংজ্ঞায়িত কোনও ক্রিয়াকলাপ থেকে ফিরে আসা কোনও স্থানীয় নয় return
scala> def f: String = {
| val g = () => { return "test" }
| g()
| "not this"
| }
f: String
scala> f
res4: String = test
যেখানে স্থানীয় পদ্ধতি থেকে ফিরে আসা কেবল সেই পদ্ধতি থেকে ফিরে আসে।
scala> def f2: String = {
| def g(): String = { return "test" }
| g()
| "is this"
| }
f2: String
scala> f2
res5: String = is this
for (a <- List(1, 2, 3)) { return ... }
? এটি বন্ধ হয়ে যায়-
return
ফাংশন থেকে একটি মান ফিরে আসুন, এবং কিছু ফর্ম escape
বা break
বা continue
পদ্ধতি থেকে ফেরত আসবে।
ফাংশন ফল উত্পন্ন করার জন্য একটি ক্রিয়াকলাপটি আর্গুমেন্টের একটি তালিকা সহ আহ্বান করা যেতে পারে। একটি ফাংশন একটি প্যারামিটার তালিকা, একটি শরীর, এবং ফলাফল ধরণের আছে। কোনও শ্রেণি, বৈশিষ্ট্য বা সিঙ্গলটন অবজেক্টের সদস্য হওয়া ফাংশনগুলিকে পদ্ধতিগুলি বলা হয় । অন্যান্য ফাংশনের অভ্যন্তরের সংজ্ঞায়িত ফাংশনগুলিকে স্থানীয় ফাংশন বলা হয়। ফলাফলের ধরণের ইউনিট সহ কার্যগুলি প্রক্রিয়া বলে। উত্স কোডে বেনামে ফাংশনগুলি ফাংশন আক্ষরিক বলে। চলাকালীন সময়ে ফাংশন লিটারালগুলি ফাংশন মান হিসাবে পরিচিত বস্তুগুলিতে ইনস্ট্যান্ট করা হয়।
স্কালার দ্বিতীয় সংস্করণে প্রোগ্রামিং। মার্টিন ওডারস্কি - লেক্স চামচ - বিল ভেনার্স
বলুন আপনার একটি তালিকা আছে
scala> val x =List.range(10,20)
x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
একটি পদ্ধতি নির্ধারণ করুন
scala> def m1(i:Int)=i+2
m1: (i: Int)Int
একটি ফাংশন সংজ্ঞায়িত করুন
scala> (i:Int)=>i+2
res0: Int => Int = <function1>
scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
তর্ক গ্রহণ করার পদ্ধতি
scala> m1(2)
res3: Int = 4
ভাল সঙ্গে ফাংশন সংজ্ঞায়িত
scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>
কাজ করার পক্ষে যুক্তি ptionচ্ছিক
scala> p(2)
res4: Int = 4
scala> p
res5: Int => Int = <function1>
আর্গুমেন্ট টু মেথড বাধ্যতামূলক
scala> m1
<console>:9: error: missing arguments for method m1;
follow this method with `_' if you want to treat it as a partially applied function
নীচের টিউটোরিয়ালটি পরীক্ষা করুন যা মেথ ভি ভি ফাংশন সহ ডিফের অন্যান্য উদাহরণগুলির সাথে উদাহরণগুলির সাথে অন্যান্য পার্থক্যগুলি পাস করার ব্যাখ্যা করে, ভেরিয়েবল হিসাবে ফাংশনটি ব্যবহার করে, ফাংশন ফিরিয়েছে এমন ফাংশন তৈরি করে
এখানে একটি সুন্দর নিবন্ধ আছে যা থেকে আমার বিবরণ অধিকাংশ নেয়া হয়। আমার বোঝাপড়া সম্পর্কে ফাংশন এবং পদ্ধতিগুলির একটি সংক্ষিপ্ত তুলনা। আশা করি এটা সাহায্য করবে:
কার্যাদি : এগুলি মূলত একটি বস্তু। আরও স্পষ্টভাবে, ফাংশনগুলি হ'ল প্রয়োগ পদ্ধতিযুক্ত বস্তু; অতএব, তাদের ওভারহেড থাকার কারণে এগুলি পদ্ধতির তুলনায় কিছুটা ধীর। এটি স্থিতিশীল পদ্ধতির মতো এই অর্থে যে তারা অনুরোধ করা কোনও বস্তুর চেয়ে স্বাধীন। ফাংশনের একটি সাধারণ উদাহরণ হ'ল শুকনোর মতো:
val f1 = (x: Int) => x + x
f1(2) // 4
উপরের লাইনটি কোনও বস্তুকে অন্য 1 যেমন অবজেক্ট 1 = অবজেক্ট 2 হিসাবে বরাদ্দ করা ছাড়া কিছুই নয়। প্রকৃতপক্ষে আমাদের উদাহরণের অবজেক্ট 2 একটি বেনাম ফাংশন এবং বাম দিকটি কোনও কারণে একটি বস্তুর ধরণ পায়। অতএব, এখন f1 একটি অবজেক্ট (ফাংশন)। বেনামে ফাংশনটি আসলে ফাংশন 1 [ইন্ট, ইনট] এর একটি উদাহরণ, যার অর্থ ইনপ টাইপের 1 পরামিতি এবং ইনট টাইপের রিটার্ন মান সহ একটি ফাংশন। আর্গুমেন্ট ছাড়াই এফ 1 কল করা আমাদের বেনামে ফাংশনটির স্বাক্ষর দেবে (আন্ত => অন্তঃ =)
পদ্ধতি : এগুলি বস্তু নয় বরং শ্রেণীর উদাহরণ হিসাবে বরাদ্দ করা হয়েছে, কোনও বস্তু। সি ++ তে জাভা বা সদস্য ফাংশনগুলির মতো হুবহু একই (যেমন রাফি খাতচাদুরিয়ান এই প্রশ্নের মন্তব্যে উল্লেখ করেছেন ) এবং ইত্যাদি। পদ্ধতির একটি সাধারণ উদাহরণ হ'ল শুকনোর মতো:
def m1(x: Int) = x + x
m1(2) // 4
উপরের লাইনটি কোনও সাধারণ মূল্য নির্ধারণ নয় তবে একটি পদ্ধতির সংজ্ঞা। আপনি যখন দ্বিতীয় লাইনের মতো 2 এর মান সহ এই পদ্ধতিটি চালু করবেন, এক্সটি 2 এর সাথে প্রতিস্থাপিত হবে এবং ফলাফল গণনা করা হবে এবং আপনি আউটপুট হিসাবে 4 পাবেন। এখানে কেবল এম 1 লিখলে আপনি একটি ত্রুটি পাবেন কারণ এটি পদ্ধতি এবং ইনপুট মানটি প্রয়োজন। _ ব্যবহার করে আপনি বেলোয়ের মতো কোনও কার্যে একটি পদ্ধতি নির্ধারণ করতে পারেন:
val f2 = m1 _ // Int => Int = <function1>
এখানে রব নরিসের একটি দুর্দান্ত পোস্ট যা পার্থক্যটি ব্যাখ্যা করে, এখানে একটি টিএল; ডিআর
স্কালায় পদ্ধতিগুলি মান নয়, তবে ফাংশনগুলি। আপনি এমন একটি ফাংশন নির্মাণ করতে পারেন যা method-বিস্তারের মাধ্যমে কোনও পদ্ধতিতে প্রতিনিধিত্ব করে (আন্ডারস্কোর জিনিসটিকে অনুসরণ করে) y
নিম্নলিখিত সংজ্ঞা সহ:
একটি পদ্ধতি ডিএফ দ্বারা সংজ্ঞায়িত কিছু এবং মান একটি মান যা আপনি একটি ভালকে নির্ধারণ করতে পারেন
সংক্ষেপে ( ব্লগ থেকে এক্সট্রাক্ট ):
আমরা যখন কোনও পদ্ধতি সংজ্ঞায়িত করি তখন আমরা দেখতে পাই যে আমরা এটিকে এটি নির্ধারণ করতে পারি না val
।
scala> def add1(n: Int): Int = n + 1
add1: (n: Int)Int
scala> val f = add1
<console>:8: error: missing arguments for method add1;
follow this method with `_' if you want to treat it as a partially applied function
val f = add1
আরো উল্লেখ্য টাইপ এর add1
, যা স্বাভাবিক মনে হচ্ছে না; আপনি টাইপের একটি ভেরিয়েবল ঘোষণা করতে পারবেন না (n: Int)Int
। পদ্ধতির মান হয় না।
যাইহোক, expansion-বিস্তৃতি পোস্টফিক্স অপারেটর যুক্ত করে (η উচ্চারণ করা হয় "এটা"), আমরা পদ্ধতিটিকে একটি ফাংশন মান হিসাবে রূপান্তর করতে পারি। এর প্রকারটি নোট করুন f
।
scala> val f = add1 _
f: Int => Int = <function1>
scala> f(3)
res0: Int = 4
এর প্রভাব _
নীচের সমতুল্য সম্পাদন করা হয়: আমরা একটি Function1
উদাহরণ তৈরি করি যা আমাদের পদ্ধতিতে প্রতিনিধিত্ব করে।
scala> val g = new Function1[Int, Int] { def apply(n: Int): Int = add1(n) }
g: Int => Int = <function1>
scala> g(3)
res18: Int = 4
স্কেলা ২.১।-এ, ফাংশনগুলির বিপরীতে পদ্ধতিগুলি গ্রহণ করতে বা ফিরে আসতে পারে
যাইহোক, এই বিধিনিষেধগুলি পলিমারফিক ফাংশন প্রকার # 4672 দ্বারা ডটটিতে (স্কালা 3) তুলে নেওয়া হয়েছে , উদাহরণস্বরূপ, ডটি সংস্করণ 0.23.0-আরসি 1 নীচের বাক্য গঠনটি সক্ষম করে
পরামিতি টাইপ করুন
def fmet[T](x: List[T]) = x.map(e => (e, e))
val ffun = [T] => (x: List[T]) => x.map(e => (e, e))
অন্তর্নিহিত পরামিতি ( প্রসঙ্গের পরামিতি)
def gmet[T](implicit num: Numeric[T]): T = num.zero
val gfun: [T] => Numeric[T] ?=> T = [T] => (using num: Numeric[T]) => num.zero
নির্ভরশীল প্রকার
class A { class B }
def hmet(a: A): a.B = new a.B
val hfun: (a: A) => a.B = hmet
আরও উদাহরণের জন্য পরীক্ষা / চালানো / পলিমারফিক-ফাংশন.স্কালা দেখুন
ব্যবহারিকভাবে, একটি স্কালা প্রোগ্রামারকে সঠিকভাবে ফাংশন এবং পদ্ধতিগুলি সঠিকভাবে ব্যবহার করতে নিম্নলিখিত তিনটি বিধি জানতে হবে:
def
এবং ফাংশন আক্ষরিক দ্বারা সংজ্ঞায়িত =>
ফাংশনগুলি। এটি স্কেল ইন প্রোগ্রামিংয়ের বইয়ের 143 পৃষ্ঠা, অধ্যায় 8 এ সংজ্ঞায়িত হয়েছে, চতুর্থ সংস্করণ।someNumber.foreach(println)
স্কালায় প্রোগ্রামিংয়ের চারটি সংস্করণের পরে, দুটি গুরুত্বপূর্ণ ধারণাটি: ফাংশন এবং ফাংশন মানকে আলাদা করতে এটি এখনও একটি বিষয় is কারণ সমস্ত সংস্করণগুলি একটি স্পষ্ট ব্যাখ্যা দেয় না। ভাষার স্পেসিফিকেশন খুব জটিল। আমি উপরের নিয়মগুলি সহজ এবং নির্ভুল পেয়েছি।