একটি ফাংশন সংজ্ঞায়িত করতে "ডিএফ" এবং "ভাল" এর মধ্যে পার্থক্য কী


214

পার্থক্য কি:

def even: Int => Boolean = _ % 2 == 0

এবং

val even: Int => Boolean = _ % 2 == 0

উভয়কেই বলা যেতে পারে even(10)


হাই, Int => Booleanমানে কি ? আমি মনে করি def foo(bar: Baz): Bin = expr
সংজ্ঞামূলক সংজ্ঞাটি

@ জিউউ এর অর্থ হল যে ফাংশন 'এমনকি' একটি আর্গুমেন্ট হিসাবে একটি ইন্ট গ্রহণ করে এবং একটি বুলিয়ানকে মান ধরণের হিসাবে প্রদান করে। সুতরাং আপনি 'এমনকি (3)' কল করতে পারেন যা বুলিয়ানকে 'মিথ্যা' বলে মূল্যায়ন করে
ডেনিস লোবর

@ ডেনিসলবর আপনার জবাবের জন্য ধন্যবাদ! এই সিনট্যাক্স সম্পর্কে কোন রেফারেন্স?
জিউউ

@Ziu আমি মূলত Odersky এর Coursera কোর্সের থেকে এটা খুঁজে পাওয়া যায় নি - coursera.org/learn/progfun1 । আপনি এটি শেষ করার পরে, আপনি বুঝতে পারবেন 'প্রকার => প্রকারের' অর্থ কী
ডেনিস লোবর

উত্তর:


325

পদ্ধতি def evenকলটিতে মূল্যায়ন করে এবং প্রতিবার নতুন ফাংশন তৈরি করে (এর নতুন উদাহরণ Function1)।

def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false

val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

সঙ্গে defআপনি প্রতি কলের নতুন ফাংশন পেতে পারেন:

val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1049057402
test()
// Int = -1049057402 - same result

def test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -240885810
test()
// Int = -1002157461 - new result

valসংজ্ঞায়িত হলে মূল্যায়ন, def- যখন ডাকা হয়:

scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing

scala> def even: Int => Boolean = ???
even: Int => Boolean

scala> even
scala.NotImplementedError: an implementation is missing

মনে রাখবেন যে তৃতীয় বিকল্প যে: lazy val

এটি যখন প্রথমবার বলা হয় তা মূল্যায়ন করে:

scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>

scala> even
scala.NotImplementedError: an implementation is missing

তবে FunctionNপ্রতিবার একই ফলাফল (একই ক্ষেত্রে একই ক্ষেত্রে ) ফেরত দেয় :

lazy val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

lazy val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1068569869
test()
// Int = -1068569869 - same result

কর্মক্ষমতা

val সংজ্ঞায়িত হলে মূল্যায়ন।

defপ্রতিটি কলের মূল্যায়ন করে, তাই valএকাধিক কল করার চেয়ে কার্য সম্পাদন আরও খারাপ হতে পারে । আপনি একক কল দিয়ে একই কর্মক্ষমতা পাবেন। এবং কোনও কল ছাড়াই আপনি কোনও ওভারহেড পাবেন না def, তাই আপনি এটি কয়েকটি সংখ্যক শাখায় ব্যবহার না করলেও আপনি এটি সংজ্ঞায়িত করতে পারেন।

একটি দিয়ে lazy valআপনি একটি অলস মূল্যায়ন পাবেন: আপনি এটি কয়েকটি শাখায় ব্যবহার না করলেও আপনি এটি সংজ্ঞায়িত করতে পারেন এবং এটি একবার বা কখনই মূল্যায়ন করে না, তবে আপনার প্রতিটি অ্যাক্সেসে ডাবল চেক লকিং থেকে আপনি একটি সামান্য ওভারহেড পাবেন lazy val

@ সার্জবর্চ উল্লেখ করেছেন যে আপনি পদ্ধতিটি সংজ্ঞায়িত করতে পারেন এবং এটি দ্রুততম বিকল্প:

def even(i: Int): Boolean = i % 2 == 0

তবে আপনার যদি ফাংশন রচনাটির জন্য বা উচ্চতর অর্ডার ফাংশনগুলির (যেমন filter(even)) সংকলকটির জন্য কোনও ফাংশন (পদ্ধতি নয়) প্রয়োজন হয় তবে আপনি যখনই এটি ফাংশন হিসাবে ব্যবহার করছেন তখন আপনার পদ্ধতি থেকে কোনও ফাংশন তৈরি করবে, সুতরাং পারফরম্যান্সের তুলনায় কিছুটা খারাপ হতে পারে val


আপনি দয়া করে পারফরম্যান্স সম্পর্কে তাদের তুলনা করুন? প্রতিটি বার evenডাকা হয় ফাংশন মূল্যায়ন করা কি গুরুত্বপূর্ণ নয় ?
আমির করিমি

2
defকোনও পদ্ধতি নির্ধারণ করতে ব্যবহার করা যেতে পারে এবং এটি দ্রুততম বিকল্প। @ এ কারিমি
প্রদর্শনীর নাম

2
মজাদার জন্য: ২.১২ even eq even,।
som-snytt

সি ++ এর মতো ইনলাইন ফাংশনগুলির কোনও ধারণা আছে? আমি সি ++ বিশ্ব থেকে আসছি, সুতরাং আমার অজ্ঞতা ক্ষমা করুন।
অ্যানিমেগোফাইন

2
@animageofmine স্কালা সংকলক পদ্ধতিগুলি ইনলাইন করার চেষ্টা করতে পারে। এর জন্য @inlineবৈশিষ্ট্য রয়েছে । তবে এটি ফাংশনগুলিকে ইনলাইন করতে পারে না কারণ ফাংশন কল applyকোনও ফাংশন অবজেক্টের ভার্চুয়াল পদ্ধতিতে কল । জেভিএম কিছু পরিস্থিতিতে এই জাতীয় কলগুলিকে অনুগ্রহ ও ইনলাইন করতে পারে, তবে সাধারণভাবে নয়।
সেনিয়া

24

এই বিবেচনা:

scala> def even: (Int => Boolean) = {
             println("def"); 
             (x => x % 2 == 0)
       }
even: Int => Boolean

scala> val even2: (Int => Boolean) = {
             println("val");
             (x => x % 2 == 0)
       }
val //gets printed while declaration. line-4
even2: Int => Boolean = <function1>

scala> even(1)
def
res9: Boolean = false

scala> even2(1)
res10: Boolean = false

আপনি পার্থক্য দেখতে পান কি? সংক্ষেপে:

Def : প্রতিটি কল করার জন্য even, এটি evenআবার পদ্ধতির বডিটিকে কল করে । কিন্তু even2অর্থাত Val , ফাংশন শুধুমাত্র একবার যখন ঘোষণা (এবং অত: পর এটা ছাপে সক্রিয়া করা হয় valলাইন 4 এবং কখনও) এবং একই আউটপুট প্রতিবার এটি অ্যাক্সেস ব্যবহার করা হয়। উদাহরণস্বরূপ এটি করার চেষ্টা করুন:

scala> import scala.util.Random
import scala.util.Random

scala> val x = { Random.nextInt }
x: Int = -1307706866

scala> x
res0: Int = -1307706866

scala> x
res1: Int = -1307706866

যখন xআরম্ভ করা হয়, তখন ফিরে আসা মানটির Random.nextIntচূড়ান্ত মান হিসাবে সেট করা হয় x। পরবর্তী সময় xআবার ব্যবহার করা হয়, এটি সর্বদা একই মান প্রদান করবে।

আপনি অলসভাবে আরম্ভ করতে পারেন x। অর্থাত্ প্রথমবার এটি ব্যবহৃত হয় এটি আরম্ভ করা হয় এবং ঘোষণার সময় নয়। উদাহরণ স্বরূপ:

scala> lazy val y = { Random.nextInt }
y: Int = <lazy>

scala> y
res4: Int = 323930673

scala> y
res5: Int = 323930673

6
আমি মনে করি আপনার ব্যাখ্যাটি এমন কিছু বোঝাতে পারে যা আপনি চান না। even2একবার 1এবং একবার সাথে দু'বার কল করার চেষ্টা করুন 2। প্রতিটি কলে আপনি বিভিন্ন উত্তর পাবেন। সুতরাং, printlnপরবর্তী কলগুলিতে মৃত্যুদন্ড কার্যকর না করা অবস্থায় আপনি বিভিন্ন কল থেকে একই ফলাফল পাবেন না even2। কেন printlnপুনরায় মৃত্যুদণ্ড কার্যকর করা হবে না, এটি একটি আলাদা প্রশ্ন।
মেলস্টন

1
এটা আসলে খুব আকর্ষণীয়। এটি ভাল এর ক্ষেত্রে এমনকি সমান 2 এর মতো, ভ্যালাকে একটি প্যারামিটারাইজড মান হিসাবে মূল্যায়ন করা হয়। সুতরাং হ্যাঁ একটি ভাল সঙ্গে আপনি ফাংশন মূল্যায়ন, এর মান। মুদ্রণটি মূল্যায়িত মানের অংশ নয়। এটি মূল্যায়নের অংশ তবে মূল্যায়নের মান নয়। এখানে কৌশলটি হ'ল মূল্যায়িত মানটি আসলে একটি প্যারামিটারাইজড মান, যা কিছু ইনপুট নির্ভর করে। স্মার্ট জিনিস
মাটডিমন

1
@ মেলস্টন ঠিক! এটাই আমি বুঝতে পেরেছি, সুতরাং আউটপুট পরিবর্তনের সময় কেন মুদ্রণটি আবার সম্পাদন হবে না?
অর

1
@ অর যা সান 2 দ্বারা ফিরে আসে তা আসলে একটি ফাংশন (এমনকি 2 এর সংজ্ঞা শেষে প্যারেন্থাইজড এক্সপ্রেশন)। সেই ফাংশনটি আসলে প্রতিটি বার আপনি যখনই আবেদন করেন তখন আপনি এমনকি 2 এ পৌঁছানোর প্যারামিটারটি দিয়ে ডাকা হয়।
মেলস্টন

5

এটা দেখ:

  var x = 2 // using var as I need to change it to 3 later
  val sq = x*x // evaluates right now
  x = 3 // no effect! sq is already evaluated
  println(sq)

আশ্চর্যজনকভাবে, এটি 9 টি নয় 4 টি মুদ্রণ করবে! ভাল (এমনকি ভ্যার) অবিলম্বে মূল্যায়ন করে নির্ধারিত হয়।
এখন ডিএফ এ ভাল পরিবর্তন করুন .. এটি 9 মুদ্রণ করবে! Def একটি ফাংশন কল .. এটি যতবার ডাকে ততবার এটি মূল্যায়ন করবে।


1

ভাল অর্থাত্ "বর্গ" স্কালার সংজ্ঞা দ্বারা স্থির হয়। এটি ঘোষণার ঠিক সময়ে মূল্যায়ন করা হয়, আপনি পরে পরিবর্তন করতে পারবেন না। অন্যান্য উদাহরণগুলিতে, যেখানে এমনকি 2 টিও ভাল, তবে এটি ফাংশন স্বাক্ষর হিসাবে ঘোষিত হয়েছে "(Int => বুলিয়ান)", সুতরাং এটি কোনও প্রকারের নয়। এটি একটি ফাংশন এবং এর মানটি নিম্নোক্ত অভিব্যক্তি দ্বারা সেট করা হয়

   {
         println("val");
         (x => x % 2 == 0)
   }

স্কালা ভাল সম্পত্তি হিসাবে, আপনি বর্গ হিসাবে একই নিয়ম এমনকি 2, অন্য ফাংশন বরাদ্দ করতে পারবেন না।

কেন eval2 ভাল ফাংশন কল করে বার বার "ভাল" মুদ্রণ করা হচ্ছে না?

মূল কোড:

val even2: (Int => Boolean) = {
             println("val");
             (x => x % 2 == 0)
       }

আমরা জানি, স্কালায় উপরের ধরণের প্রকাশের শেষ বিবৃতিটি (ভিতরে {..}}) আসলে বাম দিকে ফিরে আসে। সুতরাং আপনি এমনকি "x => x% 2 == 0" ফাংশনে সেট করে শেষ করেন যা আপনি 2 ধরণের জন্য যেমন ঘোষিত টাইপের সাথে মেলে (অর্থাত্>> বুলিয়ান), তাই সংকলক খুশি। এখন এমনকি 2 কেবল "(x => x% 2 == 0)" ফাংশনটির দিকে নির্দেশ করে (প্রিন্টলান ("ভাল") এর আগে অন্য কোনও বিবৃতি নয়) ইত্যাদি। বিভিন্ন পরামিতির সাথে ইভেন্ট 2 চালানো আসলে "(x => x% 2) কে আহ্বান করবে == 0) "কোড, কেবলমাত্র ইভেন্ট 2 দিয়ে সেভ করা আছে।

scala> even2(2)
res7: Boolean = true

scala> even2(3)
res8: Boolean = false

এই আরও স্পষ্ট করতে, নিম্নলিখিত কোডের বিভিন্ন সংস্করণ নিম্নলিখিত।

scala> val even2: (Int => Boolean) = {
     |              println("val");
     |              (x => { 
     |               println("inside final fn")
     |               x % 2 == 0
     |             })
     |        }

কি হবে ? আপনি যখন এমনকি 2 () কল করেন তখন এখানে আমরা বারবার প্রিন্টেড "ফাইনাল এফএন" দেখতে পাই।

scala> even2(3)
inside final fn
res9: Boolean = false

scala> even2(2)
inside final fn
res10: Boolean = true

scala> 

1

যেমন একটি সংজ্ঞা কার্যকর করা def x = e এক্সপ্রেশন মূল্যায়ন করবে না। স্থির ই এর মূল্যায়ন যখনই এক্স করা হয়।

বিকল্পভাবে, স্কালা একটি মান সংজ্ঞা সরবরাহ করে val x = e, যা সংজ্ঞাটির মূল্যায়নের অংশ হিসাবে ডান-হাতের মূল্যায়ন করে। যদি পরবর্তীকালে x ব্যবহার করা হয়, তবে এটি তাত্ক্ষণিক ই এর প্রাক-গণিত মান দ্বারা প্রতিস্থাপিত হবে, যাতে এক্সপ্রেশনটি আবার মূল্যায়নের প্রয়োজন হয় না।


0

এছাড়াও, ভ্যালু মূল্য মূল্যায়ন। যার অর্থ ডান দিকের অভিব্যক্তি সংজ্ঞা চলাকালীন মূল্যায়ন করা হয়। যেখানে নাম মূল্যায়ন দ্বারা Def হয়। এটি ব্যবহার না করা পর্যন্ত এটি মূল্যায়ন করবে না।


0

উপরের সহায়ক জবাব ছাড়াও, আমার অনুসন্ধানগুলি হ'ল:

def test1: Int => Int = {
x => x
}
--test1: test1[] => Int => Int

def test2(): Int => Int = {
x => x+1
}
--test2: test2[]() => Int => Int

def test3(): Int = 4
--test3: test3[]() => Int

উপরেরটি দেখায় যে "ডিএফ" হ'ল একটি পদ্ধতি (শূন্য আর্গুমেন্ট প্যারামিটার সহ) যা অনুরোধ করা হলে "ফাংশন"> ইনট => ইনট "প্রদান করে।

কার্যসমূহে পদ্ধতির রূপান্তরটি এখানে ভালভাবে ব্যাখ্যা করা হয়েছে: https://tpolecat.github.io/2014/06/09/ স্মরণার্থী- ফাংশনস html


0

REPL এ,

scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean

scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda$1157/1017502292@57a0aeb8

ডিএফ মানে call-by-name, চাহিদার উপর মূল্যায়ন

ভাল মানে call-by-value, আরম্ভের সময় মূল্যায়ন করা


এই পুরানো প্রশ্নের সাথে এবং ইতিমধ্যে জমা দেওয়া অনেক উত্তর সহ, আপনার উত্তরটি বিদ্যমান উত্তরগুলিতে প্রদত্ত তথ্য থেকে কীভাবে আলাদা হয় বা যুক্ত হয় তা ব্যাখ্যা করা প্রায়শই সহায়ক।
jwvh
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.