لقد حصلت على وظيفة في مكتبة محلية تساعد في تنظيم مجموعتها من الكتب القديمة. وكثيرًا ما يبحث الطلاب الروّاد عن اقتباسات لا يتذكرونها إلا جزئيًا ليستشهدوا بها في أوراقهم الدراسية. وبدلًا من أن تقرأ كل كتاب يدويًا من الغلاف إلى الغلاف، تقرر بناء أداة صغيرة تفحص الكتب بحثًا عن هذه الاقتباسات الجزئية.
ابحث في الملفات عن الأسطر التي تطابق سلسلة نصية للبحث، ثم أرجع جميع الأسطر المطابقة.
يبحث أمر grep في Unix في الملفات عن الأسطر التي تطابق تعبيرًا نمطيًا.
مهمتك هي تنفيذ أمر grep مبسّط يدعم البحث عن سلاسل نصية ثابتة.
يأخذ الأمر grep ثلاثة وسائط:
ثم يقرأ محتويات الملفات المحددة (بالترتيب المحدد)، ويجد الأسطر التي تحتوي على السلسلة النصية للبحث، وأخيرًا يُرجع تلك الأسطر بالترتيب الذي وُجدت به. عند البحث في عدة ملفات، يُسبق كل سطر مطابق باسم الملف والنقطتين الرأسيتين (':').
يدعم الأمر grep العلامات التالية:
-n أضف رقم السطر والنقطتين الرأسيتين (':') في بداية كل سطر من الإخراج، مع وضع الرقم بعد اسم الملف (إن وُجد).-l أخرج أسماء الملفات التي تحتوي على سطر مطابق واحد على الأقل فقط.-i طابق باستخدام مقارنة غير حساسة لحالة الأحرف.-v اعكس عمل البرنامج، واجمع كل الأسطر التي لا تطابق.-x ابحث فقط عن الأسطر التي تطابق فيها السلسلة النصية للبحث السطر بأكمله.على عكس بقية التمارين، يتطلب grep التفاعل مع «العالم الخارجي»: قراءة الملفات، والتعامل مع أخطاء النظام، والطباعة إلى stdout.
في Lean، يتم التفاعل مع النظام عادةً داخل الموناد IO، وهو يسمح بحدوث آثار جانبية في بيئة معزولة دون التأثير على الحالة النقية لمعظم الدوال الأخرى.
يسمح Lean باستدعاء ملف كسكربت، إما مباشرةً كسكربت مستقل عبر lean --run أو باستخدام lake.
لمشروع Lean نقطة دخول واحدة، وهي دالة تُسمى main، وتأخذ List String يحوي جميع الوسائط الممرَّرة إليها.
ولمحاكاة تشغيل Grep.lean كملف تنفيذي، تُمرَّر الوسائط بالطريقة نفسها في هذا التمرين.
يوفر Lean دوال للتعامل مع الملفات داخل الموناد IO.FS.
على سبيل المثال، يمكن استخدام IO.FS.readFile لقراءة محتويات ملف في مسار معين، على شكل String.
بدلًا من إرجاع قيمة، يتطلب هذا التمرين كتابة النتائج إلى المخرج القياسي أو الخطأ القياسي. توجد دوال في Lean لهذا الغرض.
على عكس الأخطاء في Except، فإن استثناءات IO هي في الواقع استثناءات وقت التشغيل.
يمكنك استخدام try/catch للتعامل معها:
try
/-
code that may possibly raise an exception
-/
catch msg =>
/-
code that is executed only if an exception was thrown
-/