প্রযুক্তিগতভাবে, আপনি কোনও কম্পিউটারে চালিত যে কোনও প্রোগ্রাম অশুচি কারণ এটি অবশেষে "এই মানটিকে" এর মধ্যে নিয়ে যান eax
"এবং" এই মানটিকে eax
" বিষয়বস্তুতে যুক্ত করুন" এর মতো নির্দেশনাগুলিতে সংকলন করে যা অপরিষ্কার। এটি খুব সহায়ক নয়।
পরিবর্তে, আমরা কালো বাক্সগুলি ব্যবহার করে বিশুদ্ধতা সম্পর্কে চিন্তা করি । যদি কিছু কোড সর্বদা একই আউটপুট উত্পাদন করে যখন একই ইনপুট দেয় তখন তা খাঁটি হিসাবে বিবেচিত হয়। এই সংজ্ঞা অনুসারে, নীচের ফাংশনটি বিশুদ্ধ এমনকি যদিও অভ্যন্তরীণভাবে এটি একটি অশুচি মেমো টেবিল ব্যবহার করে।
const fib = (() => {
const memo = [0, 1];
return n => {
if (n >= memo.length) memo[n] = fib(n - 1) + fib(n - 2);
return memo[n];
};
})();
console.log(fib(100));
আমরা ইন্টার্নালগুলির বিষয়ে চিন্তা করি না কারণ আমরা বিশুদ্ধতার জন্য যাচাই করার জন্য একটি ব্ল্যাক বক্স পদ্ধতি ব্যবহার করছি। একইভাবে, আমাদের কোনও যত্ন নেই যে সমস্ত কোডই শেষ পর্যন্ত অশুচি মেশিনের নির্দেশিকায় রূপান্তরিত হয় কারণ আমরা একটি ব্ল্যাক বক্স পদ্ধতি ব্যবহার করে বিশুদ্ধতার কথা ভাবছি। অভ্যন্তরীণ গুরুত্বপূর্ণ নয়।
এখন, নিম্নলিখিত ফাংশন বিবেচনা করুন।
const greet = name => {
console.log("Hello %s!", name);
};
greet("World");
greet("Snowman");
greet
কাজটি কি খাঁটি না অপবিত্র? আমাদের ব্ল্যাক বক্স পদ্ধতি অনুসারে, যদি আমরা এটিকে একই ইনপুট দেয় (যেমন World
) তবে এটি সর্বদা পর্দায় একই আউটপুট প্রিন্ট করে (যেমন Hello World!
)। এই অর্থে, এটা কি খাঁটি নয়? না এইটা না. এটি শুদ্ধ না হওয়ার কারণ হ'ল আমরা স্ক্রিনে কিছু মুদ্রণকে পার্শ্ব প্রতিক্রিয়া হিসাবে বিবেচনা করি। আমাদের ব্ল্যাক বক্স যদি পার্শ্ব প্রতিক্রিয়া তৈরি করে তবে তা খাঁটি নয়।
পার্শ্ব প্রতিক্রিয়া কী? এখানেই রেফারেন্সিয়াল স্বচ্ছতার ধারণাটি কার্যকর। যদি কোনও ফাংশন উল্লেখযোগ্যভাবে স্বচ্ছ হয় তবে আমরা সেই ফাংশনের অ্যাপ্লিকেশনগুলি সর্বদা তাদের ফলাফলের সাথে প্রতিস্থাপন করতে পারি। নোট করুন যে এটি ফাংশন ইনলাইনিংয়ের মতো নয় ।
ফাংশন ইনলাইনিংয়ে, আমরা প্রোগ্রামের শব্দার্থবিজ্ঞান পরিবর্তন না করে ফাংশনের বডি দিয়ে একটি ফাংশনের অ্যাপ্লিকেশনগুলি প্রতিস্থাপন করি। তবে প্রোগ্রামের শব্দার্থক শব্দ পরিবর্তন না করে সর্বদা স্বচ্ছ ফাংশনটি তার রিটার্ন মান দিয়ে প্রতিস্থাপন করা যায়। নিম্নলিখিত উদাহরণ বিবেচনা করুন।
console.log("Hello %s!", "World");
console.log("Hello %s!", "Snowman");
এখানে, আমরা সংজ্ঞাটি অন্তর্ভুক্ত করেছি greet
এবং এটি প্রোগ্রামটির শব্দার্থবিজ্ঞানের কোনও পরিবর্তন ঘটেনি।
এখন, নীচের প্রোগ্রামটি বিবেচনা করুন।
এখানে, আমরা greet
ফাংশনটির অ্যাপ্লিকেশনগুলি তাদের রিটার্ন মানগুলির সাথে প্রতিস্থাপন করেছি এবং এটি প্রোগ্রামটির শব্দার্থবিজ্ঞানের পরিবর্তন ঘটায়। আমরা আর পর্দায় অভিবাদন মুদ্রণ করছি না। মুদ্রণকে একটি পার্শ্ব প্রতিক্রিয়া হিসাবে বিবেচনা করা হয় এবং এ কারণেই greet
ফাংশনটি অপরিষ্কার। এটি উল্লেখযোগ্যভাবে স্বচ্ছ নয়।
এখন, আরেকটি উদাহরণ বিবেচনা করা যাক। নিম্নলিখিত প্রোগ্রাম বিবেচনা করুন।
const main = async () => {
const response = await fetch("https://time.akamai.com/");
const serverTime = 1000 * await response.json();
const timeDiff = time => time - serverTime;
console.log("%d ms", timeDiff(Date.now()));
};
main();
স্পষ্টতই, main
ফাংশনটি অপরিষ্কার। তবে, timeDiff
কাজটি কি খাঁটি না অপরিষ্কার? যদিও এটি নির্ভর করে serverTime
যেটি অশুচি নেটওয়ার্ক কল থেকে আসে, এটি এখনও উল্লেখযোগ্যভাবে স্বচ্ছ কারণ এটি একই ইনপুটগুলির জন্য একই ফলাফলগুলি প্রদান করে এবং কারণ এর কোনও পার্শ্ব প্রতিক্রিয়া নেই।
Zerkms সম্ভবত এই বিষয়ে আমার সাথে একমত হবে না। তার উত্তরে তিনি বলেছিলেন যে dollarToEuro
নিম্নলিখিত উদাহরণের কাজটি অপরিষ্কার কারণ "এটি আইওর উপর ট্রান্সজিটিভলি নির্ভর করে।"
const exchangeRate = fetchFromDatabase(); // evaluates to say 0.9 for today;
const dollarToEuro = (x, exchangeRate) => {
return x * exchangeRate;
};
আমাকে তার সাথে একমত হতে হবে কারণ এটি exchangeRate
একটি ডাটাবেস থেকে এসেছে তা অপ্রাসঙ্গিক। এটি একটি অভ্যন্তরীণ বিশদ এবং কোনও ফাংশনের বিশুদ্ধতা নির্ধারণের জন্য আমাদের ব্ল্যাক বক্স পদ্ধতিটি অভ্যন্তরীণ বিশদগুলির যত্ন করে না।
খাঁটিভাবে কার্যকরী ভাষায় হাস্কেলের মতো, স্বেচ্ছাসেবী আইও প্রভাবগুলি কার্যকর করার জন্য আমাদের কাছে একটি পালানোর হ্যাচ রয়েছে। এটি বলা unsafePerformIO
হয় এবং নামটি থেকে বোঝা যায় আপনি যদি এটি সঠিকভাবে ব্যবহার না করেন তবে এটি নিরাপদ নয় কারণ এটি রেফারেনশিয়াল স্বচ্ছতা ভঙ্গ করতে পারে। তবে, আপনি কী করছেন তা যদি আপনি জানেন তবে এটি ব্যবহার করা পুরোপুরি নিরাপদ।
এটি সাধারণত প্রোগ্রামের শুরুতে কনফিগারেশন ফাইলগুলি থেকে ডেটা লোড করার জন্য ব্যবহৃত হয়। কনফিগার ফাইলগুলি থেকে ডেটা লোড করা একটি অপরিচিত আইও অপারেশন। যাইহোক, আমরা প্রতিটি কার্যের ইনপুট হিসাবে ডেটা পাস করে বোঝা হতে চাই না। সুতরাং, আমরা যদি ব্যবহার করি unsafePerformIO
তবে আমরা শীর্ষ স্তরে ডেটা লোড করতে পারি এবং আমাদের সমস্ত খাঁটি ফাংশন অপরিবর্তনীয় বৈশ্বিক কনফিগার ডেটার উপর নির্ভর করতে পারে।
মনে রাখবেন যে কোনও ফাংশন কোনও কনফিগার ফাইল, ডাটাবেস বা একটি নেটওয়ার্ক কল থেকে লোড হওয়া কিছু ডেটার উপর নির্ভর করে, তার অর্থ এই নয় যে ফাংশনটি অপরিষ্কার।
যাইহোক, আসুন আপনার আসল উদাহরণটি বিবেচনা করুন যার বিভিন্ন শব্দার্থবিজ্ঞান রয়েছে।
let exchangeRate = fetchFromDatabase(); // evaluates to say 0.9 for today;
const dollarToEuro = (x) => {
return x * exchangeRate;
};
dollarToEuro(100) //90 today
dollarToEuro(100) //something else tomorrow
এখানে, আমি ধরে নিচ্ছি যে কারণ exchangeRate
হিসাবে সংজ্ঞায়িত করা হয়নি const
, প্রোগ্রামটি চলাকালীন এটি সংশোধিত হতে চলেছে। যদি এটি dollarToEuro
হয় তবে অবশ্যই এটি একটি অশুচি ফাংশন কারণ যখন exchangeRate
সংশোধন করা হবে তখন তা রেফারেন্সিয়াল স্বচ্ছতা ভঙ্গ করবে।
তবে, যদি exchangeRate
ভেরিয়েবলটি সংশোধন না করা হয় এবং ভবিষ্যতে কখনই সংশোধন করা হয় না (অর্থাত্ এটি যদি ধ্রুবক মান হয়), তবে এটি সংজ্ঞায়িত করা সত্ত্বেও let
, এটি রেফারেন্সিয়াল স্বচ্ছতা ভঙ্গ করবে না। সেক্ষেত্রে, dollarToEuro
প্রকৃতপক্ষে একটি বিশুদ্ধ ফাংশন।
মনে রাখবেন যে exchangeRate
আপনি যখন প্রোগ্রামটি আবার চালাবেন ততবার মান বদলাতে পারে এবং এটি রেফারেন্সিয়াল স্বচ্ছতা ভঙ্গ করবে না। প্রোগ্রামটি চলাকালীন পরিবর্তিত হলে এটি কেবল উল্লেখযোগ্য স্বচ্ছতা ভঙ্গ করে।
উদাহরণস্বরূপ, আপনি যদি আমার timeDiff
উদাহরণটি একাধিকবার চালান তবে আপনি বিভিন্ন মান serverTime
এবং এর জন্য বিভিন্ন ফলাফল পাবেন। তবে serverTime
প্রোগ্রামটি চলাকালীন কখনই এর মান পরিবর্তন হয় না তাই timeDiff
ফাংশনটি খাঁটি।
function myNumber(n) { this.n = n; }; myNumber.prototype.valueOf = function() { console.log('impure'); return this.n; }; const n = new myNumber(42); add(n, 1);