এটি কি খাঁটি কাজ?


117

বেশিরভাগ উত্স নিম্নলিখিত দুটি বৈশিষ্ট্য হিসাবে একটি বিশুদ্ধ ফাংশন সংজ্ঞায়িত:

  1. এটির রিটার্ন মান একই আর্গুমেন্টের জন্য একই।
  2. এর মূল্যায়নের কোনও পার্শ্ব প্রতিক্রিয়া নেই।

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

বিশুদ্ধ:

const add = (x, y) => x + y;

add(2, 4); // 6

অশুদ্ধ:

let x = 2;

const add = (y) => {
  return x += y;
};

add(4); // x === 6 (the first time)
add(4); // x === 10 (the second time)

এটি সহজেই দেখতে পাওয়া যায় যে ২ য় ফাংশন পরবর্তী কলগুলির জন্য বিভিন্ন আউটপুট দেয়, যার ফলে প্রথম শর্তটি লঙ্ঘন করা হয়। এবং তাই, এটি অপরিষ্কার।

এই অংশটি আমি পেয়েছি।


এখন, আমার প্রশ্নের জন্য, এই ফাংশনটি বিবেচনা করুন যা প্রদত্ত পরিমাণকে ডলারে ইউরোতে রূপান্তর করে:

(সম্পাদনা - constপ্রথম লাইনে ব্যবহার করা হচ্ছে। letআগে অজান্তেই ব্যবহার করা হয়েছে ))

const exchangeRate =  fetchFromDatabase(); // evaluates to say 0.9 for today;

const dollarToEuro = (x) => {
  return x * exchangeRate;
};

dollarToEuro(100) //90 today

dollarToEuro(100) //something else tomorrow

ধরুন আমরা একটি ডিবি থেকে এক্সচেঞ্জের হার আনছি এবং এটি প্রতিদিন পরিবর্তিত হয়।

এখন, আজ আমি এই ফাংশনটিকে কতবার কল করি না কেন , এটি আমাকে ইনপুটটির জন্য একই আউটপুট দেবে 100। যাইহোক, এটি আমাকে আগামীকাল একটি আলাদা আউটপুট দিতে পারে। আমি নিশ্চিত নই যে এটি প্রথম শর্ত লঙ্ঘন করে কিনা।

আইওডাব্লু, ফাংশনটিতে নিজেই ইনপুটটি পরিবর্তনের জন্য কোনও যুক্তি ধারণ করে না, তবে এটি কোনও বাহ্যিক ধ্রুবকটির উপর নির্ভর করে যা ভবিষ্যতে পরিবর্তিত হতে পারে। এই ক্ষেত্রে এটি একেবারে নিশ্চিত যে এটি প্রতিদিন পরিবর্তিত হবে। অন্যান্য ক্ষেত্রে, এটি ঘটতে পারে; এটা নাও পারে।

আমরা যেমন ফাংশন শুদ্ধ ফাংশন বলতে পারি। যদি উত্তরটি না হয়, তবে আমরা কীভাবে এটির একটি হতে পারি?


6
জেএস এর মতো এ জাতীয় গতিময় ভাষার বিশুদ্ধতা একটি খুব জটিল বিষয়:function myNumber(n) { this.n = n; }; myNumber.prototype.valueOf = function() { console.log('impure'); return this.n; }; const n = new myNumber(42); add(n, 1);
zerkms

29
বিশুদ্ধতার অর্থ হল আপনি আপনার প্রোগ্রামের আচরণ পরিবর্তন না করেই কোড স্তরে ফলাফল ফলাফলের সাথে ফাংশন কলটি প্রতিস্থাপন করতে পারেন।
বব

1
পার্শ্ব প্রতিক্রিয়াটি কী কী এবং আরও তাত্ত্বিক পরিভাষা সম্পর্কে আরও কিছুটা জানতে, দেখুন cs.stackexchange.com/questions/116377/…
গিলস 'এস-অশুভ হওয়া বন্ধ করুন'

3
আজ, কর্মটি হয় (x) => {return x * 0.9;}। আগামীকাল, আপনার একটি আলাদা ফাংশন হবে যা খাঁটিও হতে পারে, সম্ভবত (x) => {return x * 0.89;}। লক্ষ্য করুন যে প্রতিবার (x) => {return x * exchangeRate;}এটি চালানোর সময় একটি নতুন ফাংশন তৈরি হয় এবং সেই ফাংশনটি খাঁটি কারণ exchangeRateপরিবর্তন করতে পারে না।
ব্যবহারকারী 253751

2
এটি একটি অপরিষ্কার ফাংশন, আপনি যদি এটি খাঁটি করতে চান তবে আপনি const dollarToEuro = (x, exchangeRate) => { return x * exchangeRate; }; খাঁটি ফাংশনটির জন্য ব্যবহার করতে পারেন , Its return value is the same for the same arguments.সর্বদা 1 সেকেন্ড, 1 দশক ধরে রাখা উচিত .. পরে যাই হোক না কেন
বিকশ তিওয়ারি

উত্তর:


133

dollarToEuroএর ফেরত মান একটি বাহিরে পরিবর্তনশীল যে যুক্তি নয় উপর নির্ভর করে; সুতরাং, ফাংশন অপরিষ্কার।

উত্তরে হ্যাঁ, তবে কীভাবে আমরা ফাংশনটি খাঁটি হতে রিফেক্টর করব?

একটি বিকল্প প্রবেশ করানো হয় exchangeRate। এই বার, প্রতিটি বার আর্গুমেন্ট হয় (something, somethingElse)আউটপুট গ্যারান্টিযুক্ত হয় something * somethingElse:

const exchangeRate =  fetchFromDatabase(); // evaluates to say 0.9 for today;

const dollarToEuro = (x, exchangeRate) => {
  return x * exchangeRate;
};

নোট করুন যে কার্যকরী প্রোগ্রামিংয়ের জন্য আপনার এড়ানো উচিত let- constপুনরায় নিয়োগ এড়ানোর জন্য সর্বদা ব্যবহার করুন ।


6
ফাংশনটি বিশুদ্ধ হওয়ার জন্য ফ্রি ভেরিয়েবল না থাকা প্রয়োজন নয় : const add = x => y => x + y; const one = add(42);এখানে উভয়ই addএবং oneখাঁটি ফাংশন।
zerkms

7
const foo = 42; const add42 = x => x + foo;<- এটি আর একটি খাঁটি ফাংশন, যা আবার বিনামূল্যে ভেরিয়েবল ব্যবহার করে।
zerkms

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

17
আমি মনে করি আপনি এবং @ জারকিম উভয়ই ভুল। তুমি ভাবছ যে মনে dollarToEuroআপনার উত্তর উদাহরণে ফাংশন অশুদ্ধ কারণ এটা বিনামূল্যে পরিবর্তনশীল উপর নির্ভর করে exchangeRate। এটা অযৌক্তিক। Zerkms হিসাবে উল্লেখ করেছেন যে, কোনও ফাংশনটির বিশুদ্ধতার সাথে মুক্ত ভেরিয়েবল রয়েছে কিনা তা সম্পর্কিত কোনও সম্পর্ক নেই। তবে জের্কামগুলিও ভুল কারণ তিনি বিশ্বাস করেন যে dollarToEuroফাংশনটি অশুচি, কারণ এটি exchangeRateকোনও ডেটাবেস থেকে আসে তার উপর নির্ভর করে । তিনি বলেছেন যে এটি অপরিষ্কার কারণ এটি "এটি ট্রানজিটিভভাবে আইওর উপর নির্ভর করে।"
এডিট এম শাহ '

9
(বিরাম) আবার, এটি অযৌক্তিক কারণ এটি প্রস্তাব করে যে dollarToEuroএটি অশুচি কারণ exchangeRateএকটি মুক্ত পরিবর্তনশীল। এটি সুপারিশ করে যে যদি exchangeRateএকটি মুক্ত পরিবর্তনশীল না ছিল, অর্থাত্ যদি এটি একটি যুক্তি হয়, তবে dollarToEuroখাঁটি হত। সুতরাং, এটি সুপারিশ করে যে dollarToEuro(100)অপরিষ্কার তবে dollarToEuro(100, exchangeRate)খাঁটি। এটি স্পষ্টতই অযৌক্তিক কারণ উভয় ক্ষেত্রেই আপনি নির্ভর করছেন exchangeRateযা একটি ডাটাবেস থেকে আসে। পার্থক্যটি হ'ল ফাংশনের exchangeRateমধ্যে একটি মুক্ত পরিবর্তনশীল কিনা dollarToEuro
এডিট এম শাহ

76

প্রযুক্তিগতভাবে, আপনি কোনও কম্পিউটারে চালিত যে কোনও প্রোগ্রাম অশুচি কারণ এটি অবশেষে "এই মানটিকে" এর মধ্যে নিয়ে যান 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এবং এটি প্রোগ্রামটির শব্দার্থবিজ্ঞানের কোনও পরিবর্তন ঘটেনি।

এখন, নীচের প্রোগ্রামটি বিবেচনা করুন।

undefined;
undefined;

এখানে, আমরা 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ফাংশনটি খাঁটি।


3
এটি খুব তথ্যপূর্ণ ছিল। ধন্যবাদ। এবং আমি constআমার উদাহরণে ব্যবহার করতে চাইছি ।
স্নোম্যান

3
আপনি যদি ব্যবহারের মানে না করেন constতবে dollarToEuroফাংশনটি সত্যই খাঁটি। exchangeRateআপনি যদি প্রোগ্রামটি আবার চালান তবে মানটির পরিবর্তনের একমাত্র উপায় । সেক্ষেত্রে পুরানো প্রক্রিয়া এবং নতুন প্রক্রিয়া আলাদা। সুতরাং, এটি রেফারেন্সিয়াল স্বচ্ছতা ভঙ্গ করে না। এটি বিভিন্ন যুক্তি দিয়ে দুবার একটি ফাংশন কল করার মতো। আর্গুমেন্টগুলি ভিন্ন হতে পারে তবে ফাংশনটির মধ্যে আর্গুমেন্টের মান স্থির থাকে।
এডিট এম শাহ

3
আপেক্ষিকতা সম্পর্কে সামান্য তত্ত্বের মতো এই শব্দ: ধ্রুবকগুলি কেবল তুলনামূলকভাবে ধ্রুবক, একেবারে নয়, চলমান প্রক্রিয়াটির সাথে সম্পর্কিত। স্পষ্টতই এখানে সঠিক উত্তর। +1 টি।
বব

5
আমি "অপরিষ্কারের সাথে একমত নই কারণ এটি অবশেষে" এই মানটিকে ইক্সে স্থানান্তরিত করুন "এবং" এই মানটি ইক্সের বিষয়বস্তুগুলিতে যুক্ত করুন "এর মতো নির্দেশনাগুলিতে সংকলিত হয় If eaxযদি সাফ করা হয় - কোনও লোড বা একটি পরিষ্কার মাধ্যমে - কোড নির্বিশেষে নির্বিচারে থেকে যায় আর কী ঘটছে তা এবং সেইজন্য পবিত্র অন্যথায়, খুব ব্যাপক
3Dave

3
@ বার্গি: আসলে, অপরিবর্তনীয় মূল্যবোধের বিশুদ্ধ ভাষায়, পরিচয় অপ্রাসঙ্গিক। কিনা দুই রেফারেন্স যা একই মান নির্ণয় করা একই বস্তুর বা বিভিন্ন বস্তুর দুটি রেফারেন্স পারে শুধুমাত্র দ্বারা পালন করা mutating রেফারেন্স একজনের কাছ থেকে বস্তু এবং কিনা মান যখন অন্য উল্লেখের মাধ্যমে উদ্ধার করা পরিবর্তন দেখে। মিউটেশন ছাড়া পরিচয় অপ্রাসঙ্গিক হয়ে যায়। (যেমন রিচ হিকি বলবেন: পরিচয় সময়ের সাথে
অনেকগুলি

23

একজন মি-পিউরিস্টের একটি উত্তর (যেখানে "আমি" আক্ষরিক অর্থেই আমি, যেহেতু আমি মনে করি যে এই প্রশ্নের কোনও একক রীতিগত "সঠিক" উত্তর নেই):

জেএস-এর মতো গতিশীল ভাষায় বানরের প্যাচ বেস প্রকারের অনেকগুলি সম্ভাবনা রয়েছে, বা বৈশিষ্ট্যগুলি ব্যবহার করে কাস্টম প্রকারগুলি তৈরি করা হয়েছে Object.prototype.valueOfযেমন কোনও ফাংশন কেবল এটি দেখলে খাঁটি কিনা তা বলা অসম্ভব, যেহেতু এটি ফোন করতে চায় যে তারা চায় কিনা পার্শ্ব প্রতিক্রিয়া উত্পাদন।

একটি ডেমো:

const add = (x, y) => x + y;

function myNumber(n) { this.n = n; };
myNumber.prototype.valueOf = function() {
    console.log('impure'); return this.n;
};

const n = new myNumber(42);

add(n, 1); // this call produces a side effect

আমার-বাস্তববাদী এর একটি উত্তর:

থেকে উইকিপিডিয়া থেকে খুব সংজ্ঞা

কম্পিউটার প্রোগ্রামিংয়ে একটি খাঁটি ফাংশন একটি ফাংশন যাতে নিম্নলিখিত বৈশিষ্ট্য থাকে:

  1. এর রিটার্ন মান একই আর্গুমেন্টের জন্য একই (স্থানীয় স্থিতিশীল ভেরিয়েবল, অ-স্থানীয় ভেরিয়েবল, পরিবর্তনীয় রেফারেন্স যুক্তি বা I / O ডিভাইসগুলির ইনপুট স্ট্রিমগুলির সাথে কোনও পার্থক্য নয়)।
  2. এর মূল্যায়নের কোনও পার্শ্ব প্রতিক্রিয়া নেই (স্থানীয় স্ট্যাটিক ভেরিয়েবল, অ-স্থানীয় ভেরিয়েবল, পরিবর্তনীয় রেফারেন্স আর্গুমেন্ট বা I / O স্ট্রিমগুলির কোনও রূপান্তর)।

অন্য কথায়, এটি কেবল কোনও ফাংশনটি কীভাবে আচরণ করে তা কার্যকর করে তা নয়। এবং যতক্ষণ না কোনও নির্দিষ্ট ক্রিয়াকলাপ এই 2 টি বৈশিষ্ট্য ধারণ করে - এটি ঠিক কতটা বাস্তবায়িত হয়েছিল তা নির্বিশেষে খাঁটি।

এখন আপনার ফাংশনে:

const exchangeRate =  fetchFromDatabase(); // evaluates to say 0.9 for today;

const dollarToEuro = (x, exchangeRate) => {
  return x * exchangeRate;
};

এটি অপরিষ্কার কারণ এটি প্রয়োজনীয়তা 2 এর যোগ্যতা অর্জন করে না: এটি অস্থায়ীভাবে IO এর উপর নির্ভর করে।

আমি উপরের বিবৃতিটি ভুল বলে সম্মত, বিশদের জন্য অন্য উত্তরটি দেখুন: https://stackoverflow.com/a/58749249/251311

অন্যান্য প্রাসঙ্গিক সংস্থানসমূহ:


4
@ meটিজে ক্রাউডারকে জিরকাম হিসাবে উত্তর প্রদান করেছেন।
zerkms

2
হ্যাঁ, জাভাস্ক্রিপ্ট সহ এটি আত্মবিশ্বাসের সাথে সম্পর্কিত, গ্যারান্টি নয়
বব

4
@ বব ... বা এটি একটি ব্লকিং কল।
zerkms

1
@ জারকামস - ধন্যবাদ ঠিক তাই আমি 100% নিশ্চিত, আপনার add42এবং আমার মধ্যে মূল পার্থক্যটি addXহ'ল আমার xপরিবর্তন হতে পারে এবং আপনার ftপরিবর্তন করা যায় না (এবং এইভাবে, add42এর ফেরতের মান ভিত্তিতে পরিবর্তিত হয় না ft)?
টিজে ক্রাউডার

5
আমি একমত নই যে dollarToEuroআপনার উদাহরণের কাজটি অপরিষ্কার। আমি আমার উত্তরে কেন দ্বিমত জানালাম explained stackoverflow.com/a/58749249/783743
Aadit এম শাহ

14

অন্যান্য উত্তরগুলির মতো বলেছে, আপনি যেভাবে প্রয়োগ করেছেন dollarToEuro,

let exchangeRate = fetchFromDatabase(); // evaluates to say 0.9 for today;

const dollarToEuro = (x) => { return x * exchangeRate; }; 

সত্যই শুদ্ধ, কারণ প্রোগ্রামটি চলাকালীন এক্সচেঞ্জের হার আপডেট হয় না updated কনসেপ্ট্যালি, তবে dollarToEuroমনে হচ্ছে এটি একটি অপরিষ্কার ফাংশন হওয়া উচিত , এতে এটি সর্বশেষতম এক্সচেঞ্জ রেট যা-ই ব্যবহার করে। এই তাত্পর্যটি বোঝানোর সহজ উপায় হ'ল আপনি বাস্তবায়ন করেন নি dollarToEuroতবে dollarToEuroAtInstantOfProgramStart

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

  • বিনিময় করার জন্য অর্থের পরিমাণ
  • বিনিময় হারের জন্য পরামর্শের জন্য একটি historicalতিহাসিক কর্তৃপক্ষ
  • যে তারিখে লেনদেন হয়েছিল সে দিনটি (authorityতিহাসিক কর্তৃত্বকে সূচীকরণের জন্য)

এখানে historicalতিহাসিক কর্তৃপক্ষ হ'ল আপনার ডাটাবেস, এবং ধরে নিই যে ডাটাবেস আপোষহীন নয়, কোনও নির্দিষ্ট দিনে বিনিময় হারের জন্য সর্বদা একই ফলাফলটি ফিরিয়ে দেবে। সুতরাং, এই তিনটি প্যারামিটারের সংমিশ্রণের সাথে, আপনি সাধারণের একটি সম্পূর্ণ খাঁটি, স্বাবলম্বী সংস্করণ লিখতে পারেন dollarToEuro, যা দেখতে এর মতো দেখতে পারে:

function dollarToEuro(x, authority, date) {
    const exchangeRate = authority(date);
    return x * exchangeRate;
}

dollarToEuro(100, fetchFromDatabase, Date.now());

আপনার বাস্তবায়নটি historicalতিহাসিক কর্তৃত্ব এবং তত্ক্ষণাত ফাংশনটি তৈরি হওয়ার সময় লেনদেনের তারিখ উভয়ের জন্য ধ্রুবক মানগুলি ধারণ করে - historicalতিহাসিক কর্তৃত্বটি আপনার ডাটাবেস, এবং ক্যাপচারের তারিখটি আপনি প্রোগ্রামটি শুরু করার তারিখ - যা বাকী রয়েছে তা ডলারের পরিমাণ , যা কলার সরবরাহ করে। এর অপরিষ্কার সংস্করণটি dollarToEuroসর্বদা সর্বাধিক আপ-টু-ডেট মান পায় মূলত তারিখের প্যারামিটারকে স্পষ্টভাবে গ্রহণ করে, তা তাত্ক্ষণিকভাবে সেট করে ফাংশন বলা হয়, যা খাঁটি নয় কেবল কারণ আপনি কখনও একই পরামিতিগুলির সাথে দু'বার ফাংশনটি কল করতে পারবেন না।

আপনি যদি এর খাঁটি সংস্করণটি dollarToEuroপেতে চান তবে এখনও সর্বাধিক আপ টু ডেট মান পেতে পারেন, আপনি এখনও historicalতিহাসিক কর্তৃত্বকে আবদ্ধ করতে পারেন, তবে তারিখের প্যারামিটারটি আনবাউন্ডে রেখে কলারের কাছ থেকে একটি যুক্তি হিসাবে তারিখ চাইতে পারেন, শেষ পর্যন্ত এরকম কিছু সহ:

function dollarToEuro(x, date) {
    const exchangeRate = fetchFromDatabase(date);
    return x * exchangeRate;
}

dollarToEuro(100, Date.now());

@ সুমন আপনাকে স্বাগতম! আমি আরও কোড উদাহরণ যোগ করতে উত্তরটি কিছুটা আপডেট করেছি।
দ্য হ্যান্সিনেটর

8

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

আপনার যখন এই জাতীয় কোড থাকে:

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দুটি dollarToEuro(100)কলটিতে কখনও সংশোধন করা না যায় , তবে প্রথম কলটির ফলাফল মেমো-আইজ করা dollarToEuro(100)এবং দ্বিতীয় কলটি অপ্টিমাইজ করা সম্ভব। ফলাফল একই হবে, সুতরাং আমরা কেবল আগের থেকে মানটি মনে করতে পারি।

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

যদি fetchFromDatabase()নিজেই একটি ধ্রুবককে মূল্যায়ন করার একটি খাঁটি ফাংশন হয় এবং exchangeRateতা পরিবর্তনযোগ্য হয় তবে আমরা গণনার মধ্য দিয়ে এই ধ্রুবকটিকে ভাঁজ করতে পারি। কেপাইলার যা এটি কেস হিসাবে জানে আপনি মন্তব্যে একই dollarToEuro(100)কাটতি ফেলতে পারে , যা 90.0 এ মূল্যায়ন করে এবং ধ্রুব 90.0 এর সাথে সম্পূর্ণ এক্সপ্রেশনটি প্রতিস্থাপন করে।

তবে, যদি fetchFromDatabase()পার্শ্ব-প্রতিক্রিয়া হিসাবে বিবেচিত I / O সঞ্চালন না করে তবে এর নামটি সর্বনিম্ন বিস্ময়ের নীতি লঙ্ঘন করে।


8

এই ফাংশনটি খাঁটি নয়, এটি বাইরের ভেরিয়েবলের উপর নির্ভর করে, যা প্রায় স্পষ্টতই পরিবর্তন হতে চলেছে।

ফাংশন অতএব আপনি তৈরি প্রথম বিন্দু ব্যর্থ, একই যুক্তি জন্য যখন এটি একই মান ফিরে না।

এই ফাংশনটিকে "খাঁটি" করতে, exchangeRateএকটি আর্গুমেন্ট হিসাবে পাস করুন ।

এটি তখন উভয় শর্ত পূরণ করবে।

  1. একই মান এবং বিনিময় হারে পাস করার সময় এটি সর্বদা একই মান ফেরত দেয়।
  2. এটিরও কোনও পার্শ্ব প্রতিক্রিয়া নেই।

উদাহরণ কোড:

const dollarToEuro = (x, exchangeRate) => {
  return x * exchangeRate;
};

dollarToEuro(100, fetchFromDatabase())

1
"যা প্রায় স্পষ্টভাবে পরিবর্তিত হতে চলেছে" --- এটি নয়, এটি const
zerkms

7

রেফারেন্সিয়াল স্বচ্ছতা সম্পর্কে অন্যরা যে বক্তব্য রেখেছিল সেগুলি প্রসারিত করার জন্য: আমরা বিশুদ্ধতাটিকে সংজ্ঞায়িত করতে পারি যে কেবল ফাংশন কলগুলির রেফারেনশিয়াল স্বচ্ছতা হওয়া (যেমন ফাংশনের প্রতিটি কল প্রোগ্রামের শব্দার্থ পরিবর্তন না করে রিটার্ন মান দ্বারা প্রতিস্থাপন করা যেতে পারে)।

আপনি যে দুটি সম্পত্তি দিয়েছেন তা হ'ল উভয়ই রেফারেনশিয়াল স্বচ্ছতার পরিণতি । উদাহরণস্বরূপ, নিম্নলিখিত ফাংশনটি f1অশুচি, যেহেতু এটি প্রতিবার একই ফলাফল দেয় না (যে সম্পত্তিটি আপনি 1 নম্বর করেছেন):

function f1(x, y) {
  if (Math.random() > 0.5) { return x; }
  return y;
}

কেন প্রতিবার একই ফলাফল পাওয়া গুরুত্বপূর্ণ? কারণ কোনও ফাংশন কলের মান থেকে আলাদা শব্দার্থকতা পাওয়ার জন্য বিভিন্ন ফলাফল পাওয়া এক উপায় এবং সুতরাং উল্লেখযোগ্য স্বচ্ছতা ভঙ্গ করে।

ধরা যাক আমরা কোডটি লিখি f1("hello", "world"), আমরা এটি চালাই এবং ফেরতের মান পাই "hello"। যদি আমরা প্রতিটি কল সন্ধান / প্রতিস্থাপন f1("hello", "world")করি এবং তাদের সাথে প্রতিস্থাপন করব তবে "hello"আমরা প্রোগ্রামটির শব্দার্থবিজ্ঞানের পরিবর্তন করব (সমস্ত কল এখন প্রতিস্থাপন করা হবে "hello", তবে মূলত তাদের প্রায় অর্ধেকই মূল্যায়ন করবে "world")। সুতরাং কলগুলি f1রেফারেন্সিয়ালি স্বচ্ছ নয়, তাই f1অপরিষ্কার।

একটি ফাংশন কল একটি মান বিভিন্ন শব্দার্থক থাকতে পারে যে অন্য উপায় স্টেটমেন্ট সম্পাদন করে। উদাহরণ স্বরূপ:

function f2(x) {
  console.log("foo");
  return x;
}

এর রিটার্ন মান f2("bar")সর্বদা থাকবে "bar"তবে মানটির শব্দার্থক "bar"কল f2("bar")থেকে আলাদা কারণ যেহেতু পরেরটিও কনসোলে লগ হবে। একজনের পরিবর্তে অন্যটির বদলে প্রোগ্রামটির শব্দার্থবিজ্ঞানের পরিবর্তন ঘটবে, সুতরাং এটি প্রাসঙ্গিকভাবে স্বচ্ছ নয় এবং তাই f2অপরিষ্কার।

আপনার dollarToEuroফাংশনটি উল্লেখযোগ্যভাবে স্বচ্ছ কিনা (এবং তাই খাঁটি) দুটি বিষয়ের উপর নির্ভর করে:

  • আমরা উল্লেখযোগ্যভাবে স্বচ্ছ বিবেচনা করি তার 'সুযোগ'
  • কিনা exchangeRateকখনও যে 'স্কোপ' মধ্যে পরিবর্তন করতে হবে

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

যদি exchangeRateব্যবহার করা হয় varতবে এটি প্রতিটি কলের মধ্যে পরিবর্তিত হতে পারে dollarToEuro; আমাদের প্রতিটি কলের মধ্যে যে কোনও ক্যাশেড ফলাফল সাফ করা দরকার, তাই বলার মতো কোনও রেফারেন্সিয়াল স্বচ্ছতা নেই।

ব্যবহার করে constআমরা প্রোগ্রামের রানটিতে 'স্কোপ' প্রসারিত করব: dollarToEuroপ্রোগ্রামটি শেষ না হওয়া অবধি রিটার্ন মানগুলি ক্যাশে করা নিরাপদ হবে । আমরা ম্যাক্রো (লিস্পের মতো ভাষায়) ব্যবহার করে তাদের ফিরতি মানগুলির সাথে ফাংশন কলগুলি প্রতিস্থাপন করতে পারি to এই পরিমাণ বিশুদ্ধতা কনফিগারেশন মান, কমান্ডলাইন বিকল্পগুলি বা অনন্য ID এর মতো জিনিসের জন্য সাধারণ। আমরা প্রোগ্রামের এক রান নিয়ে চিন্তা নিজেদেরকে সীমাবদ্ধ তাহলে আমরা বিশুদ্ধতা সুবিধা সবচেয়ে বেশি সুবিধা পেতে, কিন্তু আমরা সতর্ক হতে হবে জুড়ে (যেমন একটি ফাইলে তথ্য সংরক্ষণ, তারপর অন্য রান এটা লোড হচ্ছে) রান। আমি এই জাতীয় ফাংশনগুলিকে একটি বিমূর্ত অর্থে "বিশুদ্ধ" বলব না (উদাহরণস্বরূপ যদি আমি অভিধানের সংজ্ঞা লিখছিলাম) তবে তাদের প্রসঙ্গে যথাযথ হিসাবে বিবেচনা করার ক্ষেত্রে কোনও সমস্যা নেই ।

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


4

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


2

আমরা যেমন ফাংশন শুদ্ধ ফাংশন বলতে পারি। যদি উত্তরটি না হয়, তবে আমরা কীভাবে এটির একটি হতে পারি?

আপনি যথাযথভাবে উল্লেখ করেছেন যে, "এটি আগামীকাল আমাকে একটি আলাদা আউটপুট দেয়" । যদি এমনটি হয় তবে উত্তরটি একটি দুর্দান্ত "না" হবে । এটি বিশেষত তাই যদি আপনার উদ্দেশ্যযুক্ত আচরণটি dollarToEuroসঠিকভাবে ব্যাখ্যা করা থাকে:

const dollarToEuro = (x) => {
  const exchangeRate =  fetchFromDatabase(); // evaluates to say 0.9 for today;
  return x * exchangeRate;
};

যাইহোক, একটি আলাদা ব্যাখ্যা উপস্থিত রয়েছে, যেখানে এটি খাঁটি হিসাবে বিবেচিত হবে:

const dollarToEuro = ( () => {
    const exchangeRate =  fetchFromDatabase();

    return ( x ) => x * exchangeRate;
} )();

dollarToEuro সরাসরি উপরে খাঁটি।


একটি সফটওয়্যার ইঞ্জিনিয়ারিং দৃষ্টিকোণ থেকে, এটি নির্ভরশীলতা ঘোষণা অপরিহার্য এর dollarToEuroফাংশন উপর fetchFromDatabase। সুতরাং, রিফ্যাক্টর dollarToEuroনিম্নলিখিত হিসাবে সংজ্ঞা :

const dollarToEuro = ( x, fetchFromDatabase ) => {
  return x * fetchFromDatabase();
};

এই ফলাফলটি সহ, fetchFromDatabaseসন্তোষজনকভাবে কাজ করে এমন ভিত্তি দেওয়া হয় , তারপরে আমরা এই সিদ্ধান্তে পৌঁছাতে পারি যে fetchFromDatabaseঅন প্রজেকশনটি dollarToEuroসন্তোষজনক হতে হবে। অথবা বিবৃতি " fetchFromDatabaseবিশুদ্ধ হয়" বোঝা dollarToEuroবিশুদ্ধ (যেহেতু fetchFromDatabaseএকটি হল ভিত্তি জন্য dollarToEuroএর স্কালে গুণক দ্বারাx

মূল পোস্ট থেকে, আমি বুঝতে পারি যে fetchFromDatabaseএটি একটি ফাংশন সময়। আসুন সেই বোঝার স্বচ্ছ করার জন্য রিফ্যাক্টরিং প্রচেষ্টাটিকে উন্নত করি, সুতরাং স্পষ্টতই যোগ্যতা অর্জন করিfetchFromDatabase খাঁটি ফাংশন হিসাবে :

fetchFromDatedia = (টাইমস্ট্যাম্প) => {/ * এখানে বাস্তবায়ন * /};

শেষ পর্যন্ত, আমি বৈশিষ্ট্যটি রিফ্যাক্টর করব নিম্নরূপ:

const fetchFromDatabase = ( timestamp ) => { /* here goes the implementation */ };

// Do a partial application of `fetchFromDatabase` 
const exchangeRate = fetchFromDatabase.bind( null, Date.now() );

const dollarToEuro = ( dollarAmount, exchangeRate ) => dollarAmount * exchangeRate();

ফলস্বরূপ, dollarToEuroকেবলমাত্র এটি প্রমাণ করে যে এটি সঠিকভাবে কল করেছে fetchFromDatabase(বা এর ডেরাইভেটিভ exchangeRate) তার একক-পরীক্ষা করা যেতে পারে ।


1
এটি খুব আলোকিত ছিল। +1 টি। ধন্যবাদ।
স্নোম্যান

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

-1

আমি একটি হাস্কেল / জেএস দ্বিভাষিক এবং হাস্কেল এমন একটি ভাষাগুলি যা ফাংশন বিশুদ্ধতার বিষয়ে একটি বড় চুক্তি করে, তাই আমি ভেবেছিলাম যে হাস্কেল এটি কীভাবে দেখেন সেখান থেকে আমি আপনাকে দৃষ্টিভঙ্গি দেব।

অন্যরা যেমন বলেছে, হাস্কেলে, একটি পরিবর্তনীয় পরিবর্তনশীল পড়া সাধারণত অশুচি বলে বিবেচিত হয়। ভেরিয়েবল এবং সংজ্ঞাগুলির মধ্যে পার্থক্য রয়েছে যে ভেরিয়েবলগুলি পরে পরিবর্তিত হতে পারে, সংজ্ঞাগুলি চিরকাল একই থাকে। তাই আপনি যদি করেছিলেন এই ছবিটিকে constতারপর (অভিমানী এটি শুধু একটি হলnumber একটি সংজ্ঞা, যা বিশুদ্ধ ব্যবহার করা হবে এবং কোন চপল অভ্যন্তরীণ গঠন আছে), যে থেকে পড়া। তবে আপনি সময়ের সাথে সাথে বিনিময় হারের পরিবর্তন করতে মডেল করতে চেয়েছিলেন এবং এর জন্য একরকম পরিবর্তনের প্রয়োজন হয় এবং তারপরে আপনি অশুচি হয়ে যান।

অশুদ্ধ যেসব ঐ প্রকারের বর্ণনা করার (আমরা তাদের "প্রভাব" কল করবো এবং তাদের ব্যবহার "effectful" হিসেবে "বিশুদ্ধ" থেকে ভিন্ন) মধ্যে Haskell, আমরা কি আপনাকে কল পারে না metaprogramming । আজকের রূপান্তর সাধারণত বোঝায় ম্যাক্রোকে যা আমার অর্থ নয়, বরং সাধারণভাবে অন্য প্রোগ্রাম লেখার জন্য একটি প্রোগ্রাম লেখার ধারণা।

এই ক্ষেত্রে, হাসকেলে, আমরা একটি শুদ্ধ গণনা লিখি যা একটি কার্যকর প্রোগ্রাম গণনা করে যা আমরা যা চাই তা করতে পারে। সুতরাং একটি হাস্কেল উত্স ফাইলের সম্পূর্ণ বিন্দু (কমপক্ষে, একটি যা একটি প্রোগ্রাম বর্ণনা করে একটি গ্রন্থাগার নয়) একটি কার্যকর প্রোগ্রাম-যা-উত্পাদিত-অকার্যকর, নামক শুদ্ধ গণনা বর্ণনা করে main। তারপরে হাস্কেল সংকলকের কাজ হ'ল এই উত্স ফাইলটি গ্রহণ করা, সেই খাঁটি গণনা সম্পাদন করা এবং সেই কার্যকর প্রোগ্রামটি বাইনারি হিসাবে নির্বাহযোগ্য হিসাবে আপনার হার্ড ড্রাইভের পরে আপনার অবসর সময়ে চালানোর জন্য রেখে দেওয়া। অন্য কথায়, খাঁটি গণনা চলার সময়ের মধ্যে (যখন সংকলকটি নির্বাহযোগ্য করে তোলে) এবং কার্যকর প্রোগ্রামটি চালিত হওয়ার সময় (যখনই আপনি নির্বাহককে চালিত করেন) একটি ব্যবধান থাকে।

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

export class Program<x> {
   // wrapped function value
   constructor(public run: () => Promise<x>) {}
   // promotion of any value into a program which makes that value
   static of<v>(value: v): Program<v> {
     return new Program(() => Promise.resolve(value));
   }
   // applying any pure function to a program which makes its input
   map<y>(fn: (x: x) => y): Program<y> {
     return new Program(() => this.run().then(fn));
   }
   // sequencing two programs together
   chain<y>(after: (x: x) => Program<y>): Program<y> {
    return new Program(() => this.run().then(x => after(x).run()));
   }
}

মূলটি হ'ল যদি আপনার কোনও হয় Program<x>তবে কোনও পার্শ্ব প্রতিক্রিয়া ঘটেনি এবং এগুলি সম্পূর্ণ কার্যকরভাবে খাঁটি সত্তা। কোনও প্রোগ্রামের মাধ্যমে কোনও ফাংশন ম্যাপিংয়ের কোনও পার্শ্ব প্রতিক্রিয়া নেই যদি না ফাংশনটি খাঁটি ফাংশন না থাকে; দুটি প্রোগ্রাম সিকোয়েন্সিং এর কোনও পার্শ্ব প্রতিক্রিয়া নেই; প্রভৃতি

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

// assuming a database library in knex, say
function getUserById(id: number): Program<{ id: number, name: string, supervisor_id: number }> {
    return new Program(() => knex.select('*').from('users').where({ id }));
}
function notifyUserById(id: number, message: string): Program<void> {
    return new Program(() => knex('messages').insert({ user_id: id, type: 'notification', message }));
}
function fetchJSON(url: string): Program<any> {
  return new Program(() => fetch(url).then(response => response.json()));
}

এবং তারপরে আপনি কোনও ইউআরএল কার্ল করতে কোনও ক্রোন জব বর্ণনা করতে পারেন এবং কিছু কর্মচারী সন্ধান করতে এবং তাদের সুপারভাইজারকে খাঁটি কার্যকরী উপায়ে অবহিত করতে পারেন

const action =
  fetchJSON('http://myapi.example.com/employee-of-the-month')
    .chain(eotmInfo => getUserById(eotmInfo.id))
    .chain(employee => 
        getUserById(employee.supervisor_id)
          .chain(supervisor => notifyUserById(
            supervisor.id,
            'Your subordinate ' + employee.name + ' is employee of the month!'
          ))
    );

মুল বক্তব্যটি হ'ল এখানে প্রতিটি ফাংশন সম্পূর্ণ বিশুদ্ধ ফাংশন; আমি আসলে action.run()এটিকে গতিতে সেট না করা পর্যন্ত কিছুই আসলে ঘটেনি । এছাড়াও আমি যেমন ফাংশন লিখতে পারি,

// do two things in parallel
function parallel<x, y>(x: Program<x>, y: Program<y>): Program<[x, y]> {
    return new Program(() => Promise.all([x.run(), y.run()]));
}

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

একইভাবে আপনার ক্ষেত্রে আমরা বিনিময় হারের সাথে পরিবর্তনগুলি বর্ণনা করতে পারি

declare const exchangeRate: Program<number>;

function dollarsToEuros(dollars: number): Program<number> {
  return exchangeRate.map(rate => dollars * rate);
}

এবং exchangeRateএমন একটি প্রোগ্রাম হতে পারে যা একটি পরিবর্তনীয় মান দেখায়,

let privateExchangeRate: number = 0;
export function setExchangeRate(value: number): Program<void> {
  return new Program(() => { privateExchangeRate = value; return Promise.resolve(undefined); });
}
export const exchangeRate: Program<number> = new Program(() => {
  return Promise.resolve(privateExchangeRate); 
});

কিন্তু তবুও, এই ফাংশন dollarsToEuros এখন একটি সংখ্যা থেকে শুরু করে একটি প্রোগ্রামের খাঁটি ফাংশন যা কোনও সংখ্যা তৈরি করে এবং আপনি এই নির্ণায়ক সমীকরণের সাথে যুক্তিটি করতে পারেন যে কোনও প্রোগ্রামের কোনও কারণ নেই যার কোনও পার্শ্ব প্রতিক্রিয়া নেই reason

অবশ্যই, ব্যয়টি হ'ল আপনাকে শেষ পর্যন্ত এটি .run() কোথাও কল করতে হবে এবং তা অপরিষ্কার। তবে আপনার গণনার সম্পূর্ণ কাঠামো একটি খাঁটি গণনা দ্বারা বর্ণনা করা যেতে পারে এবং আপনি আপনার কোডের মার্জিনে অপরিষ্কারকে ঠেলাতে পারেন।


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

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