مسیرها
/
Factor
Factor
/
تمرین‌ها
/
نوار تلگرافچی
نوار تلگرافچی

نوار تلگرافچی

تمرین یادگیری

مقدمه

شما پیشتر در channel-chatter از جریان‌ها استفاده کرده‌اید و در boatswains-bilge آن‌ها را دور انداخته‌اید. این تمرین نخستین جریان سفارشی شماست: کلاسی که پروتکل را پیاده‌سازی می‌کند تا همان کد with-input-stream / read1 / stream-read1 که روی یک <string-reader> کار می‌کرد، روی جریان شما هم کار کند.

میکسین‌ها: نیمه‌ی دیگر سلسله‌مراتب کلاس

شما TUPLE: child < parent … را از dragons-descendants می‌شناسید: سلسله‌مراتبی تک‌والدی که در آن خانه‌ها به پایین می‌رسند. Factor راه دومی هم برای گسترش گراف کلاس‌ها دارد: میکسین‌های باز. MIXIN: m کلاسی را اعلام می‌کند که هیچ خانه‌ای ندارد و کلاس‌های دیگر می‌توانند بعدها با INSTANCE: c m به آن بپیوندند. عضویت چندبه‌چند است: یک کلاس می‌تواند نمونه‌ی هر تعداد میکسین که بخواهد باشد.

پروتکل جریان‌ها از دو میکسین استفاده می‌کند تا مشخص کند یک کلاس کدام نیمه از رابط را پیاده‌سازی می‌کند:

INSTANCE: my-stream input-stream    ! readable
INSTANCE: my-stream output-stream   ! writable

یک جریان می‌تواند یکی از این دو، یا هر دو باشد. متدهای ژنریک روی input-stream (یا output-stream) آن‌گاه به هر کلاسی که به آن میکسین پیوسته است فرستاده می‌شوند؛ به این ترتیب است که read1، stream-contents، with-input-stream و غیره، که به‌صورت همگانی در دسترس‌اند، راهشان را به کلاس شما پیدا می‌کنند.

میکسین‌ها باز هستند: می‌توانید پس از اعلام میکسین، عضو تازه‌ای به آن اضافه کنید، حتی در یک واژگان دیگر. تفاوت همین‌جاست با TUPLE: < parent که در آن رابطه هنگام اعلام کلاس فرزند ثابت می‌شود.

ژنریک‌های پروتکل

ژنریک‌های پروتکل در io قرار دارند:

stream-read1         ( stream -- elt/f )
stream-read          ( n stream -- seq/f )
stream-read-unsafe   ( n buf stream -- count )
stream-write1        ( elt stream -- )
stream-write         ( seq stream -- )
stream-flush         ( stream -- )
stream-element-type  ( stream -- type )

stream-read1 بایت بعدی را برمی‌گرداند (یا در پایان جریان f را)؛ stream-write1 یک بایت می‌نویسد. stream-read-unsafe همان خواندن دسته‌ای سطح‌پایین‌تر است که بیشتر جریان‌های ورودی فراهم می‌کنند؛ stream-read روی آن ساخته شده و تخصیص حافظه را مدیریت می‌کند. stream-element-type می‌گوید که جریان با بایت (+byte+) سر و کار دارد یا با نویسه (+character+)؛ وقتی جریان دیگری را دربرمی‌گیرید، ساده‌ترین پیاده‌سازی فقط کار را به جریان زیرین واگذار می‌کند.

پاک‌سازی از destructors است

جریان‌ها دورانداختنی‌اند: یک جریان سفارشی disposable را گسترش می‌دهد و dispose* را پیاده‌سازی می‌کند. این همان چارچوبی است از boatswains-bilge که این بار روی یک کلاس جریان اعمال شده است:

TUPLE: my-stream < disposable underlying ;

: <my-stream> ( underlying -- s )
    my-stream new-disposable swap >>underlying ;

M: my-stream dispose* underlying>> dispose ;

وقتی این کار انجام شد، همه‌ی ترکیب‌کننده‌های with-… از channel-chatter به‌طور خودکار روی جریان شما کار می‌کنند.

دستورالعمل‌ها

شما اپراتور بی‌سیم تلگراف روی یک کشتی باری هستید. سیگنال از خطی پرنویز می‌رسد؛ صدای ماشین‌آلات کشتی، پارازیت جوّ، گاهی هم صحبت‌های بیگانه، همه درهم‌آمیخته با همان مورسی که در انتظارش هستید. برای گرفتن پیام، سیم را از دستگاهی به نام «نوار» عبور می‌دهید که هر چیزی جز نمادهای معتبر مورس (.، - و فاصله‌ای که حروف را از هم جدا می‌کند) را حذف می‌کند.

کار شما این است که نوار را به عنوان یک جریان ورودی سفارشی Factor بسازید.

1. نوار را تعریف کنید

یک تاپل tape تعریف کنید که از disposable ارث‌بری می‌کند و یک اسلات به نام wire برای جریان ورودی زیربنایی در خود نگه می‌دارد.

TUPLE: tape < disposable wire ;

سپس سازنده‌ی <tape> ( wire -- tape ) را بنویسید. از new-disposable (نه new) استفاده کنید تا چارچوب تخریب‌گر نوار را ثبت کند، و جریان زیربنایی را در اسلات wire ذخیره کنید.

2. به میکسین input-stream بپیوندید

tape را به عنوان یک input-stream اعلام کنید:

INSTANCE: tape input-stream

این کار باعث می‌شود ترکیب‌گرهای پیش‌فرض پروتکل به کلاس شما فرستاده شوند.

3. یک نماد مورس را بخوانید

M: tape stream-read1 ( tape -- elt/f ) را پیاده‌سازی کنید. بایت‌هایی را از سیم زیربنایی بخوانید تا به یکی از CHAR: .، CHAR: - یا CHAR: \s (فاصله) برسید. همان بایت را برگردانید. اگر سیم f را برگرداند (پایان جریان)، شما هم f را برگردانید؛ کار نوار تمام است.

"x.y -ab cz" <string-reader> <tape>
[ stream-read1 ] [ stream-read1 ] [ stream-read1 ] tri
! => CHAR: . CHAR: - CHAR: \s

4. نوع عنصر را واگذار کنید

M: tape stream-element-type ( tape -- type ) را با واگذاری به سیم پیاده‌سازی کنید؛ نوار نوع عناصری که خوانده می‌شوند را تغییر نمی‌دهد.

5. پاک‌سازی کنید

M: tape dispose* ( tape -- ) را پیاده‌سازی کنید. چارچوب متد شما را دقیقاً یک بار به ازای هر dispose فراخوانی می‌کند؛ فقط سیم زیربنایی را آزادسازی کنید.

با آماده بودن این پنج قطعه، نوار مانند یک جریان ورودی معمولی کار می‌کند؛ with-input-stream، stream-read و دیگر واژه‌های پروتکل همگی به‌طور خودکار به متدهای شما فرستاده می‌شوند.

ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Factor Exercism

آماده‌اید نوار تلگرافچی را شروع کنید؟

در Exercism ثبت‌نام کنید تا Factor را همراه با 47 مفهوم163 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.