Common Lisp-এ প্রিন্টার নামে একটি ধারণা আছে, যার মধ্যে Lisp ডেটার টেক্সট রূপ লেখার সব ফাংশন পড়ে। এমন একটি ফাংশন হলো format, যেটি প্রোগ্রামারকে নিজের ইচ্ছেমতো ডেটা ফরম্যাট করার সুযোগ দেয়।
সাধারণভাবে Lisp প্রিন্টার আর format-এর ক্ষমতা বেশ বড় একটি বিষয়; এখানে format ব্যবহারের প্রাথমিক বিষয়গুলো বর্ণনা করা হবে।
format ফাংশনটি অন্তত দুটি আর্গুমেন্ট নেয়: যে স্ট্রিমে প্রিন্ট করা হবে সেটি, আর একটি কন্ট্রোল স্ট্রিং, যেটি ঠিক করে কী প্রিন্ট হবে এবং কীভাবে প্রিন্ট হবে।
স্ট্রিম আলাদা একটি ধারণা, সেটি অন্য জায়গায় বর্ণনা করা হবে। আপাতত যতটুকু জানা দরকার তা হলো, প্রিন্টিং কাজটি স্ট্রিমে করা হয়, আর এই আর্গুমেন্টের জন্য দুটি বিশেষ মান আছে: t এবং nil। t মানে স্ট্যান্ডার্ড আউটপুটে প্রিন্ট করা (আসলে যে স্ট্রিমের সাথে *standard-output* ভ্যারিয়েবলটি বাঁধা আছে)। আর nil মানে একটি স্ট্রিং তৈরি করে সেটি রিটার্ন করা।
মনে রাখবেন, format সর্বদা nil-এ ইভ্যালুয়েট হয়, শুধু শেষের সেই ক্ষেত্রটি ছাড়া, যেখানে স্ট্রিম হিসেবে nil দেওয়া হয়। সরল স্ট্রিং ইন্টারপোলেশন বা স্ট্রিং তৈরির জন্য এটি একটি কমন উপায়।
(format nil "hello world") ; => "hello world"
(format t "hello world") ; => NIL (but "hello world" is printed to standard output)
কন্ট্রোল স্ট্রিংয়ের মধ্যে "ফরম্যাট ডিরেক্টিভ" থাকতে পারে, যেগুলো format-কে বলে দেয় কী প্রিন্ট করতে হবে এবং format-এর বাকি প্যারামিটারগুলো কীভাবে ব্যাখ্যা করতে হবে। এক অর্থে কন্ট্রোল স্ট্রিংটি একটি প্রোগ্রাম, যেটি format ইন্টারপ্রেট করে চালায়। সব ডিরেক্টিভ ~ দিয়ে শুরু হয় এবং তারপর একটি ক্যারেক্টার থাকে (যেমন ~A, ~D, ~&)। ক্যারেক্টারটি বড় হাতের না ছোট হাতের, তা কোনো ব্যাপার না।
বেশিরভাগ ফরম্যাট ডিরেক্টিভ কেবল format-এর একটি আর্গুমেন্ট আউটপুটের মধ্যে ইন্টারপোলেট করে। একে বলা হয় আর্গুমেন্টটি "কনজিউম" করা। কিছু ডিরেক্টিভ কোনো আর্গুমেন্ট কনজিউম করে না, আবার কিছু একাধিক কনজিউম করে। এমনকি একটি ডিরেক্টিভ দিয়ে আর্গুমেন্ট লিস্টে এদিক-ওদিক লাফানো বা আর্গুমেন্ট বাদ দেওয়াও যায়।
খুব সাধারণ কাজে ব্যবহারযোগ্য একটি ফরম্যাট ডিরেক্টিভ হলো ~A। এটি ডেটার একটি 'হিউম্যান-রিডেবল' রূপ প্রিন্ট করে।
(format nil "Value = ~a" 10) ; => "10"
(format nil "hello ~a" "world") ; => "hello world"
(format nil "The list is: ~A" (list 1 2 3)) ; => "The list is: (1 2 3)"
আরেকটি দরকারি ফরম্যাট ডিরেক্টিভ হলো ~S। এটি ডেটার একটি 'মেশিন-রিডেবল' রূপ প্রিন্ট করে। তৈরি হওয়া আউটপুটকে Lisp ডেটা হিসেবে ব্যাখ্যা করার সুযোগ থাকলে এটি খুবই কাজে লাগে। অনেক ক্ষেত্রেই এটি ~A-এর মতোই দেখায়, তবে লক্ষ্য করবেন, স্ট্রিংয়ের ক্ষেত্রে আউটপুটে উদ্ধৃতি চিহ্নও থাকে (অন্য কোনো স্ট্রিংয়ের ভেতরে রাখলে যা এস্কেপ করা হয়), যাতে মানটি স্ট্রিং প্যারামিটার হিসেবে আবার পড়া যায়।
(format nil "~s" 10) ; => "10"
(format nil "~s" "hello world") ; => "\"hello world\""
(format nil "~s" (list 1 2 3)) ; => "(1 2 3)"
আরও দুটি খুব দরকারি ডিরেক্টিভ হলো ~% এবং ~&। প্রথমটি একটি নিউলাইন ক্যারেক্টার আউটপুট করে, আর দ্বিতীয়টি একটি "ফ্রেশ লাইন"। পার্থক্য হলো, ~% সর্বদা একটি নিউলাইন আউটপুট করে, কিন্তু ~& কেবল তখনই একটি আউটপুট করে যখন বর্তমানে লাইনের শুরুতে নেই। এর কোনোটিই আর্গুমেন্ট কনজিউম করে না।
(format nil "~%new~%lines") ; => "
new
lines"
(format nil "~&new~&lines" ; => "new
lines"
সবশেষে, ~~ একটি সরল ডিরেক্টিভ, যেটি একটি লিটারাল ~ আউটপুট করে।
চাকরি করা প্রায় সবার মতো Layla the Lisp Alien-কেও মাঝে মাঝে রিপোর্ট তৈরি করতে হয়, যাতে অন্যরা কোনো তথ্য জেনে যায়। তিনি জিজ্ঞেস করেন, এই রিপোর্টের জন্য তার কাছে থাকা ডেটা ফরম্যাট করতে আপনি কি তাঁকে সাহায্য করতে পারবেন?
Layla-এর প্রথমে যা দরকার তা হলো একটি ফাংশন: format-quarter-value, যা দুটি প্যারামিটার নেয়, ক্যালেন্ডার ত্রৈমাসিক ও মান, এবং সেটিকে একটি রিপোর্টের জন্য ফরম্যাট করে। এর ফলাফল একটি স্ট্রিং হওয়া উচিত।
(format-quarter-value "last" 3.14) ; => "The value last quarter: 3.14"
(format-quarter-value "this" 0) ; => "The value this quarter: 0"
format-quarter-value ফাংশনের জন্য Layla আপনাকে ধন্যবাদ জানান এবং বলেন, পরবর্তী যে ফাংশনটির দরকার হবে, সেখানে এটি খুব কাজে লাগবে।
পরের রিপোর্টে দুই ত্রৈমাসিকের নাম ও মান দুই লাইনে ছাপিয়ে দেখাতে হবে।
এছাড়া আউটপুট প্রথম আর্গুমেন্ট হিসেবে দেওয়া স্ট্রিমে পাঠাতে হবে।
যেমন: (format-two-quarters t "last" 3.14 "this" 0) স্ট্যান্ডার্ড আউটপুটে নিচের ফলাফল দেবে:
The value last quarter: 3.14
The value this quarter: 0
লক্ষ্য করুন, এর চারপাশে ফাঁকা লাইন আছে।
Layla আপনাকে বলতে ভুলে গেছেন যে Lisp Alien-রা মানগুলো এমনভাবে দেখতে পছন্দ করেন, যাতে সেগুলো Lisp ডেটা হিসেবে পড়া যায়। তাই তাদের একটি নতুন ফাংশন দরকার, যা Lisp ডেটা হিসেবে পড়া যাবে (আবারও নির্দিষ্ট স্ট্রিমে):
(format-two-quarters-for-reading nil "last" 3.14 "this" 0) ; =>
"(\"The value last quarter: 3.14\" \"The value this quarter: 0\")"
Exercism-এ সাইন আপ করুন, Common Lisp ট্র্যাকের 27টি কনসেপ্ট92টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।