Common Lisp-এ অনেকগুলো ভিন্ন সমতা প্রেডিকেট আছে।
এটি অন্য প্রোগ্রামিং ভাষাগুলোর থেকে আলাদা, যেখানে সম্ভবত মাত্র একটি বা দুটি থাকে (যেমন == আর ===)।
Common Lisp-এর এসব প্রেডিকেটের মধ্যে কিছু টাইপ-নির্দিষ্ট, আবার কিছু জেনেরিক।
এখানে আলোচনা করা হবে এই শেষেরগুলো নিয়ে।
চারটি জেনেরিক সমতা প্রেডিকেট আছে, আর কীকে তারা "equal" মনে করে, সেই বিচারে তাদের কঠোরতা আলাদা।
সবচেয়ে কঠোর থেকে সবচেয়ে শিথিল ক্রমে সেগুলো হলো: eq, eql, equal আর equalp।
সংক্ষেপে কয়েকটি সংজ্ঞা (কিছু খুঁটিনাটি বাদ দিয়ে) নিচে দেওয়া হলো:
eq: সমতা বলতে বোঝায় দুটি অবজেক্ট একেবারে অভিন্ন।
যেমন:(eq 'a 'a) ; => T
(eq (list 1 2) (list 1 2)) ; => NIL
eql: সমতা বলতে বোঝায় একই টাইপ ও মানের দুটি সংখ্যা, দুটি একই ক্যারেক্টার, কিংবা অন্য যেকোনো কিছু যদি তারা eq হয়।
যেমন:(eql 1 1) ; => T
(eql #\a #\a) ; => T
(eql 1 1.0) ; => NIL
(eql #\a #\A) ; => NIL
equal: সমতা বলতে বোঝায়: দুটি তালিকা equal হয় যদি তাদের প্রতিটি এলিমেন্টও equal হয়; দুটি স্ট্রিং equal হয় যদি প্রতিটি এলিমেন্ট eql হয়; দুটি অ্যারে equal হয় যদি তারা eq হয়; আর বাকি সবকিছু equal হয় যদি তারা eql হয়।
যেমন:(equal (list 1 2) (list 1 2)) ; => T
(equal #(1 2) #(1 2)) ; => NIL
(equal "foo" "foo") ; => T
equalp: সমতা বলতে বোঝায়: স্ট্রিং আর ক্যারেক্টার তুলনা করা হয় বড়-ছোট হাতের অক্ষর নির্বিশেষে; সংখ্যা তুলনা করা হয় কিছু টাইপ কনভার্সন-সহ; তালিকা আর অ্যারে equalp হয় যদি প্রতিটি এলিমেন্টও equalp হয়, স্ট্রাকচার হয় যদি সেগুলো একই টাইপের হয় আর সব স্লট equalp হয়, আর হ্যাশ-টেবিল হয় যদি তার কী (key) ও মান equalp হয়
যেমন:(equalp "foo" "FoO") ; => T
(equalp 3 3.0) ; => T
(equalp (make-a-structure :slot1 1 :slot2 2)
(make-a-structure :slot1 1 :slot2 2)) ; => T
লেসলি দ্য লিস্প অ্যালিয়েন তাদের গোলকধাঁধা-রোবট প্রোগ্রাম করছেন (যেমনটা অল্পবয়সী লিস্প অ্যালিয়েনদের অভ্যাস) এবং কিছু সাহায্য প্রয়োজন। গোলকধাঁধাটি ধারাবাহিক কিছু ঘর নিয়ে গঠিত। প্রতিটি ঘরে কয়েকটি দরজার মধ্যে থেকে বেছে নেওয়ার সুযোগ থাকে। প্রতিটি দরজার জন্য একটি চাবি দরকার। দরজায় ভুল চাবি ব্যবহার করলে দরজাটি ফেটে যাওয়ার সম্ভাবনা থাকে (রোবটের জন্য চিন্তার কিছু নেই, কোনো ক্ষতি হবে না, তবে পোড়া দাগ ঘষে তুলে ফেলা লেসলির জন্য বেশ বিরক্তিকর)। রোবটের কাছে যদি এমন কোনো চাবি না থাকে যা দিয়ে কোনো দরজা খোলা যায়, তাহলে পুরো ঘরটাই ফেটে যাবে! (আবারও, চিন্তার কিছু নেই, ক্ষতি হবে না, তবে পরিষ্কার করা ঝামেলার হবে।)
লেসলিকে যা সাহায্য করতে হবে তা হলো প্রতিটি ঘরের জন্য রোবটকে সঠিক চাবি দেওয়া। রোবট ঘরের প্রতিটি দরজায় ক্রমানুসারে চাবি ব্যবহার করবে এবং যে দরজাটি প্রথমে খুলবে সেটি দিয়েই বেরিয়ে যাবে।
প্রতিটি টেস্ট একটি গোলকধাঁধা এবং প্রতিটি অ্যাসারশন একটি ঘর। আপনাকে প্রেডিকেট ফাংশন লিখতে হবে, যেগুলো আর্গুমেন্ট সমান হলে T এবং সমান না হলে NIL রিটার্ন করবে।
এই গোলকধাঁধায় মাত্র একটি ঘর আছে। আপনাকে এমন একটি ফাংশন দিতে হবে যা বলতে পারবে দুটি অবজেক্ট একই অবজেক্ট কি না।
উদাহরণস্বরূপ:
a ; => "pizza"
b ; => "pizza"
(key-object-identity a a) ; => T
(key-object-identity a b) ; => NIL
কারণ a এবং b একই বলে মনে হলেও তারা একই অবজেক্ট নয়।
এই গোলকধাঁধায় দুটি ঘর আছে। প্রথমটির একটি দরজা খোলা যাবে যদি আপনার চাবি বলতে পারে দুটি সংখ্যা কঠোরভাবে সমান কি না। দ্বিতীয় ঘরের জন্য এমন চাবি দরকার যা সংখ্যার সমতা যাচাইয়ে কিছুটা নমনীয়তা দেয়।
উদাহরণস্বরূপ:
a ; => 13
b ; => 13.0
c ; => 13
(key-numbers a b) ; => NIL
(key-numbers a c) ; => T
(key-numbers-of-different-types a b) ; => T
কারণ a এবং b সংখ্যাগতভাবে একই হলেও তাদের টাইপ আলাদা।
এই গোলকধাঁধায় দুটি ঘর আছে। প্রথমটির একটি দরজা খোলা যাবে যদি আপনার চাবি বলতে পারে দুটি ক্যারেক্টার কঠোরভাবে সমান কি না। দ্বিতীয় ঘরের জন্য এমন চাবি দরকার যা ক্যারেক্টারগুলোর কেস-ইনসেনসিটিভ তুলনা করতে দেয়।
উদাহরণস্বরূপ:
a ; => #\X
b ; => #\x
c ; => #\X
(key-characters a b) ; => NIL
(key-characters a c) ; => T
(key-characters-case-insensitively a b) ; => T
কারণ দুটি ক্যারেক্টার তুলনা করার সময় শুধুমাত্র খুব নমনীয় সমতা-প্রেডিকেটগুলোই কেস উপেক্ষা করে।
ক্যারেক্টারের গোলকধাঁধার মতো প্রথম ঘরের জন্য এমন চাবি দরকার যা যাচাই করে দুটি স্ট্রিং সমান কি না; দ্বিতীয় ঘরের জন্য দরকার এমন চাবি যা কেস-ইনসেনসিটিভ তুলনা করতে দেয়।
উদাহরণস্বরূপ:
a ; => "pizza"
b ; => "PIZZA"
c ; => "pizza"
(key-strings a b) ; => NIL
(key-strings a c) ; => T
(key-strings-case-insensitively a b) ; => T
কারণ দুটি স্ট্রিং তুলনা করার সময় শুধুমাত্র খুব নমনীয় সমতা-প্রেডিকেটগুলোই কেস উপেক্ষা করে।
এটি অনেক ঘরওয়ালা একটি বড় গোলকধাঁধা। প্রতিটি ঘরের জন্য এমন চাবি দরকার যা যাচাই করবে যে কনসগুলো যে জিনিসগুলো ধারণ করছে সেগুলো সমান কি না। প্রতিটি ঘর ভিন্ন ভিন্ন কনটেন্টের কনসের সমতা যাচাই করবে: সিম্বল, সংখ্যা, ক্যারেক্টার, আর কিছু ক্ষেত্রে ওই কনটেন্টগুলোর জন্য আরও নমনীয় সমতার সংজ্ঞা লাগবে।
উদাহরণস্বরূপ:
syms-a ; => (left . right)
syms-b ; => (up . down)
syms-c ; => (left . right)
chars-a ; => (#\x . #\y)
chars-b ; => (#\x . #\Y)
chars-c ; => (#\x . #\y)
nums-a ; => (13 . 23)
nums-b ; => (13 . 23.0)
nums-c ; => (13 . 23)
(key-conses-of-symbols syms-a syms-b) ; => NIL
(key-conses-of-symbols syms-a syms-c) ; => T
(key-conses-of-characters chars-a chars-b) ; => NIL
(key-conses-of-characters chars-a chars-c) ; => T
(key-conses-of-characters-case-insensitively
chars-a chars-b) ; => T
(key-conses-of-numbers nums-a nums-b) ; => NIL
(key-conses-of-numbers nums-a nums-c) ; => T
(key-conses-of-numbers-of-different-types
nums-a nums-b) ; => T
কারণ কনসের ভেতরে তাকায় এমন একটি সমতা-প্রেডিকেট থাকলেও, তুলনা করার সময় কেস বা সংখ্যার টাইপ উপেক্ষা করার জন্য সেটি যথেষ্ট নমনীয় নাও হতে পারে।
এই গোলকধাঁধাটি সহজ, এতে মাত্র দুটি ঘর আছে। প্রথমটির জন্য এমন চাবি দরকার যা যাচাই করে অ্যারেগুলো একই অ্যারে কি না। দ্বিতীয়টির জন্য এমন চাবি দরকার যা অ্যারেগুলোর কনটেন্ট যাচাই করবে।
উদাহরণস্বরূপ:
a ; => #[13 23]
b ; => #[13 23]
c ; => #[13 23.0]
(key-arrays a b) ; => NIL
(key-arrays a c) ; => NIL
(key-arrays-loosely a b) ; => T
(key-arrays-loosely a c) ; => T
কারণ শুধুমাত্র খুব নমনীয় সমতা-যাচাইকারীরাই অ্যারের কনটেন্ট সমান কি না তা যাচাই করে।
Exercism-এ সাইন আপ করুন, Common Lisp ট্র্যাকের 27টি কনসেপ্ট92টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।