লজিক ও ডিক্লারেটিভ প্রোগ্রামিং প্যারাডাইম
এই পাঠে যা শিখবেন
- ডিক্লারেটিভ প্যারাডাইমের সংজ্ঞা এবং L06-এর ইম্পারেটিভ "কীভাবে"-এর সাথে সরাসরি বৈসাদৃশ্য
- লজিক প্রোগ্রামিং-এর মূল উপাদান — ফ্যাক্ট, রুল ও কোয়েরি
- কীভাবে একটি ইনফারেন্স ইঞ্জিন বিদ্যমান ফ্যাক্ট থেকে নতুন ফ্যাক্ট স্বয়ংক্রিয়ভাবে বের করে
- Python-এ একটি ছোট ফ্যামিলি-ট্রি উদাহরণে
infer_new_factsফাংশন বাস্তবায়ন ও যাচাই
১ · ডিক্লারেটিভ প্যারাডাইম — "কী", "কীভাবে" নয়
ডিক্লারেটিভ প্রোগ্রামিংDeclarative Programmingপ্রোগ্রাম বর্ণনা করে কাঙ্ক্ষিত ফলাফল কী, ধাপে-ধাপে কীভাবে তা অর্জন করতে হবে তা নয় — আন্ডারলাইং সিস্টেম নিজেই এক্সিকিউশন-কৌশল ঠিক করে।
প্রোগ্রামে বর্ণনা করে কী ফলাফল দরকার, কীভাবে ধাপে ধাপে সেটি অর্জন করতে হবে
তা বলে দেয় না — আন্ডারলাইং সিস্টেম/ইঞ্জিন নিজেই এক্সিকিউশন-কৌশল ঠিক করে। এটি L06-এর ইম্পারেটিভ প্যারাডাইমের
"কীভাবে"-কেন্দ্রিক দর্শনের ঠিক বিপরীত। SQL একটি পরিচিত, প্রায় সব প্রোগ্রামারই কোনো-না-কোনো সময় ব্যবহার করা
ডিক্লারেটিভ ভাষার উদাহরণ — একটি SELECT কোয়েরি কাঙ্ক্ষিত রেজাল্ট সেট বর্ণনা করে, কোনো ধাপে-ধাপে
রিট্রিভাল অ্যালগরিদম লিখে দেয় না; ডেটাবেস ইঞ্জিন নিজেই ঠিক করে কীভাবে সেই ফলাফল বের করবে।
২ · লজিক প্রোগ্রামিং — ফ্যাক্ট ও রুল
লজিক প্রোগ্রামিংLogic Programmingএকটি ডিক্লারেটিভ প্যারাডাইম যেখানে প্রোগ্রাম ফ্যাক্ট ও রুল দিয়ে গঠিত, এবং একটি কোয়েরি সেই ফ্যাক্ট/রুল সন্তুষ্ট করা মান স্বয়ংক্রিয় ইনফারেন্সের মাধ্যমে খুঁজে বের করে।
(যেমন Prolog) একটি নির্দিষ্ট ডিক্লারেটিভ প্যারাডাইম — প্রোগ্রাম গঠিত হয় ফ্যাক্ট (সত্য বলে
ঘোষিত বক্তব্য, যেমন ("parent", "alice", "bob")) ও রুল (বিদ্যমান ফ্যাক্ট থেকে
কীভাবে নতুন ফ্যাক্ট অনুমান করা যায় তার বর্ণনা) দিয়ে। একটি কোয়েরি তখন সিস্টেমকে জিজ্ঞাসা করে সেই ফ্যাক্ট ও
রুল সন্তুষ্ট করে এমন মান খুঁজে বের করতে — একটি স্বয়ংক্রিয় সার্চ/ইনফারেন্স প্রক্রিয়ার (যেমন ব্যাকওয়ার্ড-চেইনিং/
রেজোলিউশন, শুধু নাম উল্লেখ করা হলো, বাস্তবায়ন এই পাঠের আওতার বাইরে) মাধ্যমে — প্রোগ্রামারের নিজের হাতে-লেখা
কোনো নির্দিষ্ট অ্যালগরিদম দিয়ে নয়।
৩ · কোড: একটি মিনি ইনফারেন্স ইঞ্জিন
নিচের কোডে একটি ছোট ফ্যামিলি-ট্রি ফ্যাক্ট-সেট এবং একটি "grandparent" রুল দেওয়া আছে —
infer_new_facts(facts, rule_fn) ফাংশনটি রুলটি সব সম্ভাব্য ফ্যাক্ট-জোড়ার ওপর প্রয়োগ করে
এবং নতুন কোনো ফ্যাক্ট বের করা যায় কি না তা রিটার্ন করে। লক্ষ্য করুন প্রোগ্রামার কোথাও লেখেননি "প্রথমে alice-এর
সন্তান খোঁজো, তারপর সেই সন্তানের সন্তান খোঁজো" — শুধু সম্পর্কটি কী তা রুল আকারে বর্ণনা করা হয়েছে।
# একটি ছোট ফ্যামিলি-ট্রি ফ্যাক্ট-সেট
facts = [
("parent", "alice", "bob"),
("parent", "bob", "carol"),
("parent", "carol", "dave"),
]
def grandparent_rule(facts):
"""রুল: parent(X,Y) ও parent(Y,Z) দুটোই সত্য হলে grandparent(X,Z) ইনফার করা যায়"""
new_facts = set()
parent_facts = [f for f in facts if f[0] == "parent"]
for (_, x, y1) in parent_facts:
for (_, y2, z) in parent_facts:
if y1 == y2: # একই মধ্যবর্তী ব্যক্তি (Y) মিলে গেলে
new_facts.add(("grandparent", x, z))
return new_facts
def infer_new_facts(facts, rule_fn):
"""রুলটি প্রয়োগ করে, বিদ্যমান ফ্যাক্ট বাদ দিয়ে শুধু সত্যিকারের নতুন ফ্যাক্টগুলো রিটার্ন করে"""
inferred = rule_fn(facts)
existing = set(facts)
return inferred - existing
inferred = infer_new_facts(facts, grandparent_rule)
print("প্রদত্ত facts:")
for f in facts:
print(" ", f)
print("\nনতুনভাবে ইনফার করা facts:")
for f in sorted(inferred):
print(" ", f)
parent(alice, bob) ও parent(bob, carol) — এই দুটোতে মধ্যবর্তী ব্যক্তি
"bob" মিলে যায়, তাই grandparent(alice, carol) ইনফার হয়। একইভাবে parent(bob, carol)
ও parent(carol, dave)-এ মধ্যবর্তী ব্যক্তি "carol" মিলে যায়, তাই grandparent(bob, dave)
ইনফার হয়। মোট দুটো নতুন ফ্যাক্ট — উভয়ই ইনপুট ফ্যাক্ট-সেটের সাথে হাতে মিলিয়ে সঠিক প্রমাণিত।
একটি রুল থেকে নতুন ফ্যাক্ট ইনফার করার প্রক্রিয়া মূলত প্রেডিকেট লজিকের মডাস পোনেন্স-এর মতো একটি ইনফারেন্স নিয়মের প্রয়োগ — Discrete Mathematics কোর্সে লজিক ও প্রুফ টেকনিকের গভীর তাত্ত্বিক ভিত্তি কভার করা হয়েছে; এখানে আমরা সেই তত্ত্বের একটি সরাসরি প্রোগ্রামিং-ল্যাঙ্গুয়েজ প্রয়োগ দেখলাম।
লজিক প্রোগ্রামিং-এ প্রোগ্রামার সম্পর্ক ও নিয়ম বর্ণনা করেন, অনুসন্ধান-অ্যালগরিদম লেখেন না।
উপরের কোডে infer_new_facts নিজেই "সার্চ ইঞ্জিন"-এর ভূমিকা পালন করেছে — সব সম্ভাব্য জোড়া
পরীক্ষা করে দেখেছে রুলটি কোথায় প্রযোজ্য। বাস্তব Prolog ইঞ্জিনগুলো এই ধারণাকেই অনেক বেশি সাধারণীকৃত ও
অপ্টিমাইজড রূপে বাস্তবায়ন করে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
SQL-এর SELECT কোয়েরিকে কেন ডিক্লারেটিভ বলা হয়, ইম্পারেটিভ নয়?
একটি SELECT কোয়েরি বর্ণনা করে কোন ফলাফল চাই ("এই শর্ত মেলে এমন সব সারি") — কিন্তু
কোথাও বলে না ডেটাবেস কীভাবে ডিস্ক থেকে পড়বে, কোন ইনডেক্স ব্যবহার করবে, বা কোন ক্রমে টেবিল স্ক্যান করবে।
সেই এক্সিকিউশন-কৌশল সম্পূর্ণভাবে ডেটাবেস ইঞ্জিনের (তার কোয়েরি অপ্টিমাইজারের) সিদ্ধান্ত — একই কোয়েরি
বিভিন্ন সময় ভিন্ন এক্সিকিউশন-প্ল্যানেও চলতে পারে, ফলাফল একই থাকা সত্ত্বেও। এই "কী চাই বলো, কীভাবে তা
ইঞ্জিনের সিদ্ধান্ত" বৈশিষ্ট্যই একে ডিক্লারেটিভ করে তোলে।
প্র ০২
উপরের কোডে যদি facts-এ আরেকটি এন্ট্রি ("parent", "dave", "eve") যোগ করা হয়, নতুন কোন grandparent ফ্যাক্ট ইনফার হবে?
grandparent(carol, eve) — কারণ এখন parent(carol, dave) ও
parent(dave, eve) দুটোই ফ্যাক্ট-সেটে আছে, এবং মধ্যবর্তী ব্যক্তি "dave" দুটোতেই মিলে যায়।
বিদ্যমান দুটো ইনফার করা ফ্যাক্ট (grandparent(alice, carol),
grandparent(bob, dave)) অপরিবর্তিত থাকবে — মোট তিনটি grandparent ফ্যাক্ট
ইনফার হবে। কোডের কোনো লজিক বদলাতে হয়নি, শুধু ইনপুট ফ্যাক্ট-সেট বড় হয়েছে।
প্র ০৩
infer_new_facts ফাংশনে শেষে inferred - existing (সেট সাবট্রাকশন) কেন করা হয়েছে — সরাসরি rule_fn(facts)-এর ফলাফলই কেন রিটার্ন করা হয়নি?
grandparent_rule সব সম্ভাব্য জোড়া পরীক্ষা করে যা ইনফার করা যায় তার সম্পূর্ণ সেট
রিটার্ন করে — এর মধ্যে এমন ফ্যাক্টও থাকতে পারে যা ইতিমধ্যে মূল facts তালিকায় সরাসরি দেওয়া
ছিল (এই নির্দিষ্ট উদাহরণে ঘটেনি, কিন্তু সাধারণভাবে ঘটতে পারে)। inferred - existing নিশ্চিত
করে ফাংশনটি শুধু সত্যিকারের নতুন (আগে থেকে জানা ছিল না এমন) ফ্যাক্ট রিটার্ন করে — একটি বাস্তব
ইনফারেন্স ইঞ্জিনের গুরুত্বপূর্ণ বৈশিষ্ট্য, নয়তো পুরোনো ও নতুন জ্ঞানের মধ্যে পার্থক্য বোঝা যেত না।
অনুশীলন
-
পরীক্ষা করুন: উপরের কোডে
facts-এ("parent", "carol", "dave")-এর একটি ডুপ্লিকেট এন্ট্রি যোগ করে Run চাপুন — ইনফার করা ফলাফলে কোনো পরিবর্তন হয় কি?না, কোনো পরিবর্তন হবে না — ইনফার করা ফলাফল একই দুটি ফ্যাক্ট থাকবে (
grandparent(alice, carol),grandparent(bob, dave)), কারণnew_factsএকটি Pythonset, এবং সেট স্বভাবতই ডুপ্লিকেট বাদ দেয়। এটি ডেমোনস্ট্রেট করে ইনফারেন্স ইঞ্জিনটি একই ফ্যাক্ট একাধিকবার প্রসেস হলেও নির্ভুল (ইডেমপোটেন্ট) থাকে। -
চিন্তা করুন: যদি একটি "great-grandparent" সম্পর্কও ইনফার করতে চান (grandparent + parent), তাহলে
grandparent_rule-এর মতো নতুন কী রুল লিখতে হবে (কোড পরিবর্তন করবেন না, শুধু চিন্তা করুন)?একটি নতুন রুল ফাংশন দরকার হবে যা ইতিমধ্যে-ইনফার-করা
grandparentফ্যাক্ট এবং মূলparentফ্যাক্ট — দুটো ভিন্ন ধরনের ফ্যাক্ট — একসাথে দেখে: যদিgrandparent(X, Y)এবংparent(Y, Z)দুটোই সত্য হয়, তাহলেgreat_grandparent(X, Z)ইনফার করা যায়। এটি দেখায় কীভাবে লজিক প্রোগ্রামিং-এ রুলগুলো একে অপরের ইনফার করা ফলাফলের ওপর ভিত্তি করে ধাপে ধাপে জটিলতর সম্পর্ক তৈরি করতে পারে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ M2 প্রোগ্রামিং প্যারাডাইম মডিউলের শেষ পাঠে যান — মাল্টি-প্যারাডাইম ভাষা ও প্যারাডাইম বেছে নেওয়া।
- আগের পাঠ L08 ফাংশনাল প্রোগ্রামিং প্যারাডাইম — আরেকটি ডিক্লারেটিভ-ঘেঁষা শৈলী, যেখানে "কী গণনা করতে হবে" এক্সপ্রেশন দিয়ে প্রকাশ করা হয়।
- পরের পাঠ L10 মাল্টি-প্যারাডাইম ল্যাঙ্গুয়েজ ও প্যারাডাইম বেছে নেওয়া — M2-এর চারটি প্যারাডাইম একসাথে দেখে কোন সমস্যায় কোনটি বেছে নেবেন তার সিদ্ধান্ত-কাঠামো।