خانه - راه اندازی اینترنت
نام تابع در برنامه نویسی چیست؟ توابع برنامه نویسی

هدف کار: 1) قوانین توصیف توابع را مطالعه کنید. 2) مهارت در استفاده از توابع هنگام نوشتن برنامه در C++ را کسب کنید.

اطلاعات نظری

ماژول اصلی برنامه ها در C++ تابع است.

تابع- یک قطعه منطقی کامل شده و قطعاً طراحی شده از یک برنامه که یک نام دارد. توابع به شما امکان می دهند وظایف محاسباتی بزرگ را به کارهای کوچکتر تقسیم کنید.

هر برنامه ++C لزوماً دارای تابعی به نام main است که بدنه برنامه است. برای همه توابع دیگر، در صورت وجود در برنامه، نمونه های اولیه باید اعلام شوند - نمادهای شماتیک که نام و شکل هر تابع در برنامه را به کامپایلر می گوید.

نحو برای یک نمونه اولیه تابع با پارامترها به صورت زیر است:

return_value_type function_name (parameter_list_with_type_indication);

توابع در C++ استاندارد (کتابخانه ای) و قابل برنامه ریزی توسط کاربر هستند.

ویژگی های استاندارد

توضیحات توابع استاندارد در فایل های موجود در برنامه با استفاده از دستور #include یافت می شود. به این گونه فایل ها، فایل های هدر می گویند. آنها پسوند h را دارند.

اشاره به نام تابع در برنامه اصلی فراخوانی تابع نامیده می شود.

فراخوانی توابع منجر به اجرای یک عمل یا محاسبه مقداری می شود که سپس در برنامه استفاده می شود.

y = sin(x); //تابع محاسبه سینوسی

تعریف تابع

به طور کلی توابع به صورت زیر تعریف می شوند:

return_value_type function_name (نوع parameter_name،...، نوع parameter_name)

عملکرد_بدن

ویژگی های قابل برنامه ریزی

توابعی که برنامه نویس خودش ایجاد می کند فرآیند نوشتن برنامه ها را ساده می کند زیرا:

    کمک به جلوگیری از برنامه نویسی مکرر، زیرا از یک تابع می توان در برنامه های مختلف استفاده کرد.

    سطح ماژولار بودن برنامه را افزایش دهید، بنابراین خواندن، ایجاد تغییرات و اصلاح خطاها را آسان تر می کند.

مثال9 .1. بیایید یک تابع ایجاد کنیم که 65 کاراکتر "*" را در یک ردیف چاپ کند. برای اینکه این تابع در برخی زمینه ها کار کند، در برنامه چاپ سربرگ گنجانده شده است. این برنامه از توابع اصلی () و () stars تشکیل شده است.

// سربرگ

#عبارتند از

const int Limit=65;

void stars (void); // تابع نمونه اولیه stars()

کوت<<"Moscow Institute of Electronic Engineering"<

// تعریف تابع stars().

برای (count=1; count<=Limit; count++)

ما به مثالی از یک تابع ساده نگاه کردیم که هیچ آرگومانی ندارد و هیچ مقداری را بر نمی گرداند.

پارامترهای تابع

بیایید به مثالی از استفاده از پارامترهای تابع نگاه کنیم.

مثال9. 2. بیایید فضای تابع ()، را بنویسیم که آرگومان آن تعداد فضاهایی است که این تابع باید چاپ کند.

#define address "Zelenograd"

#تعریف نام "انستیتو مهندسی الکترونیک مسکو"

#تعریف بخش "انفورماتیک و برنامه نویسی"

const int LIMIT=65;

#عبارتند از

فضای خالی (شماره int)؛

کوت<

spaces=(LIMIT - strlen(name))/2; // تعداد را محاسبه کنید

// نیاز به فضا دارد

کوت<

فضا((LIMIT - strlen(بخش))/2); // آرگومان - بیان

کوت<

//تعریف تابع stars().

برای (count=1; count<=LIMIT; count++)

//تعریف تابع ()space

فضای خالی (شماره int)

برای (count=1; count<=number; count++)

متغیر عدد را آرگومان رسمی می نامند. این متغیر هنگام فراخوانی تابع، مقدار آرگومان واقعی را می گیرد. به عبارت دیگر، استدلال رسمییک متغیر در تعریف زیربرنامه نامیده شده است و استدلال واقعیمقدار خاصی است که توسط برنامه فراخوانی به این متغیر اختصاص داده شده است.

اگر یک تابع برای برقراری ارتباط به بیش از یک آرگومان نیاز دارد، می‌توانید فهرستی از آرگومان‌های جدا شده با کاما را همراه با نام تابع مشخص کنید:

void printnum(int i، int j)

(کوت<<"Координаты точек”<< i << j <

مقدار ورودی تابع به دلیل وجود قابل پردازش است بحث و جدل; مقدار خروجی با استفاده از کلمه کلیدی بازگشت بازگردانده می شود.

کاربرانی که اصولاً از برنامه نویسی دور هستند به ندرت با مفاهیم توابع و رویه ها روبرو می شوند و با چیزی ریاضی و بوروکراتیک-پزشکی مرتبط هستند. در برنامه نویسی، بسیاری از زبان ها با این مفاهیم کار می کنند، با این حال، حتی متخصصان نیز گاهی اوقات نمی توانند به وضوح تفاوت بین یک تابع و یک رویه را درک کنند. مانند آن گوفر: آنجاست، اما کسی آن را نمی بیند. بیایید ببینیم که آیا تفاوت ها تا این حد نامرئی هستند یا خیر.

اصطلاحات تابع و رویه به چه معناست؟

  • تابعدر برنامه نویسی، یک زیربرنامه به تعداد دفعات مورد نیاز از زیربرنامه های دیگر فراخوانی می شود.
  • روش- قسمتی از برنامه (زیر روال) نامگذاری شده که به دفعات مورد نیاز از قسمت های بعدی برنامه به طور مکرر فراخوانی شده است.

مقایسه عملکرد و رویه

تفاوت اصلی بین یک تابع و یک رویه در نتیجه ای است که برمی گرداند. در واقع، هر دو توابع و رویه‌ها بلوک‌های منطقی غیرقابل تقسیم هستند که کد برنامه را تشکیل می‌دهند. یک تابع مقداری را برمی‌گرداند، یک رویه در اکثر زبان‌های برنامه‌نویسی این کار را نمی‌کند، یا (مثلاً در C) یک مقدار خالی را برمی‌گرداند. در مورد دوم (در C)، یک رویه نسخه فرعی یک تابع در نظر گرفته می شود.

هدر تابع حاوی کلمه "function"، یک شناسه (نام مناسب تابع)، در صورت تمایل فهرستی از پارامترها و لزوماً نوع نتیجه است. بدنه تابع باید دارای یک عملگر باشد که مقداری را به نام تابع اختصاص دهد که در نتیجه آن را برمی گرداند. سرصفحه رویه حاوی کلمه "procedure"، یک شناسه (نام رویه) و در صورت تمایل فهرستی از پارامترها است.

فراخوانی تابع به عنوان بخشی از عباراتی که در آن این عبارات استفاده می شود انجام می شود؛ فراخوانی رویه به یک دستور جداگانه نیاز دارد.

یک رویه فقط با نام فراخوانی می شود، در حالی که نام یک تابع با مقدار آن مرتبط است. در نمودارهای الگوریتم، یک فراخوانی تابع در یک بلوک خروجی یا در یک بلوک فرآیند، یک فراخوانی رویه در یک بلوک "فرآیند از پیش تعریف شده" ویژه به تصویر کشیده می شود.

تفاوت تابع و رویه در برنامه نویسی به شرح زیر است:

  • یک تابع یک مقدار را برمی گرداند، اما یک رویه این کار را نمی کند.
  • هدر تابع باید حاوی نوع نتیجه باشد.
  • بدنه تابع باید حاوی عبارتی باشد که مقداری را به نام تابع اختصاص دهد.
  • فراخوانی یک رویه نیاز به یک دستور جداگانه دارد، فراخوانی یک تابع به عنوان بخشی از یک عبارت امکان پذیر است.
  • نام رویه برای فراخوانی آن لازم است، نام تابع برای تخصیص یک مقدار مورد نیاز است.
  • در نمودارهای الگوریتم، یک فراخوانی رویه در یک بلوک جداگانه، یک فراخوانی تابع در یک فرآیند یا بلوک خروجی نشان داده می‌شود.

اساس هر برنامه کامپیوتری الگوریتم ها هستند که به صورت دستورات بیان می شوند. شخصی که کد را می نویسد می گوید، این را بگیرید، این کار را انجام دهید، این و آن را با آن انجام دهید و سپس نتیجه را همانجا خروجی بگیرید و استراحت کنید. بنابراین، برای اینکه دستورات در برنامه ها در یک آشفتگی واحد ادغام نشوند و بتوانند با یکدیگر تعامل داشته باشند، به اصطلاح در توابع و رویه ها گروه بندی می شوند. با این مفاهیم آشنا می شویم.

تابع چیست

نام توابع استفاده می شود: 1) برای ایجاد اسناد. 2) برای یک API، یعنی یک رابط برای اتصال به یک برنامه یا کل سیستم عامل هر برنامه. بنابراین، منطقی است که یک بار دیگر یادآوری کنیم که این اسامی باید قابل فهم و در صورت امکان متناسب با اقدامات انجام شده باشد.

بیایید خلاصه کنیم

بنابراین، توابع نوعی ظرف برای گروه بندی الگوریتم ها هستند. آنها:

  1. مسئول وظایف خاص؛
  2. تعامل با اشیاء دیگر؛
  3. اساس مفهومی برنامه نویسی مدرن هستند، مهم نیست که چقدر رقت انگیز به نظر می رسد.

رویه ها در واقع همان توابع هستند، البته "خالی" که چیزی را بر نمی گرداند (این تفاوت اصلی آنهاست). اینها ابزارهای کمکی هستند که برای انجام کارهای معمولی و همچنین صرفه جویی در فضا، تلاش و زمان طراحی شده اند.

انتشارات قبلی:

بیهوده نیست که من این مقاله را "توابع به عنوان بخشی جدایی ناپذیر از برنامه نویسی" نامیدم، زیرا بدون آنها، به نظر من، هیچ زبانی حق وجود ندارد. چیست؟ یک تابع جزء اصلی یک برنامه خوب نوشته شده است. این نه تنها خواندن کد را آسان تر می کند، بلکه ایده برنامه نویسی ساخت یافته را نیز به شدت تغییر می دهد. با کمک توابع، می توانید از بخش های جداگانه برنامه با ارسال هر پارامتری به آنها استفاده مجدد کنید. هیچ برنامه جدی بدون این معجزه عنصر برنامه نویسی قابل تصور نیست.

من به طور خلاصه به شما می گویم که چگونه کار می کند. تابع بلوکی از دستورالعمل هاست که برنامه شما می تواند آن ها را فراخوانی کند. وقتی به سربرگ این بلوک (نام تابع) دسترسی پیدا کرد، اجرا می شود و برخی از اقدامات مشخص شده توسط برنامه نویس را انجام می دهد. پس از آن این بلوک مقدار دریافتی را برمی گرداند و به برنامه اصلی ارسال می کند. بگذارید در عمل توضیح دهم.

به طور کلی، به نظر می رسد این است. بگذارید مختصر توضیح دهم. ما یک متغیر ایجاد می کنیم و نتیجه اجرای تابع myfunc را به آن اختصاص می دهیم، که به نوبه خود مقدار مربع کردن تعدادی اعداد را محاسبه می کند. توابع بلافاصله با شروع برنامه اجرا نمی شوند، بلکه فقط زمانی اجرا می شوند که فراخوانی شوند. شاید کمی گیج کننده باشد، اما این طور است.

چگونه یک تابع را فراخوانی کنیم؟

برای فراخوانی یک تابع، باید آن را ایجاد کنید. اگرچه توابع داخلی نیز وجود دارد. برای مثال این: cos, sin, md5, count, absو غیره برای فراخوانی آنها فقط باید مقدار مورد نظر را به متغیر اختصاص دهید.

یک آرگومان تابع مقداری است که هنگام فراخوانی به آن ارسال می کنید. آرگومان های تابع در پرانتز قرار می گیرند. هنگام ایجاد یک تابع، نام های شرطی را برای آرگومان ها مشخص می کنید. سپس این نام ها را می توان در بدنه تابع، به عنوان متغیرهای محلی استفاده کرد. بیایید به توابعی که خود کاربر ایجاد می کند برگردیم. این کار خیلی راحت انجام می شود. ابتدا بدنه تابع ایجاد می شود:

تابع hello() ( echo "Hello, world!";)

بعد بهش زنگ میزنیم علاوه بر این، اگر پارامتری نداشته باشد، به سادگی پرانتز قرار می دهیم. برای فراخوانی این تابع، فقط از خط زیر استفاده می کنیم: سلام()؛. هر تابعی همچنین می تواند با استفاده از یک کلمه رزرو شده مقداری را برگرداند برگشت. این دستور اجرای تابع را متوقف می کند و مقدار بازگشتی را به برنامه فراخوانی ارسال می کند. تابع sum($first, $second) ($r=$first + $second; return $r;) echo sum(2,5); نتیجه اجرای برنامه برابر با 7 متغیر محلی و جهانی خواهد بود

مانند هر زبان برنامه نویسی دیگری، متغیرهایی وجود دارند که فقط در یک تابع موجود هستند و متغیرهایی که در کد خود برنامه موجود هستند. چنین متغیرهایی به ترتیب محلی و سراسری نامیده می شوند. در داخل یک تابع، نمی توانید به سادگی به متغیری که خارج از تابع ایجاد شده است دسترسی داشته باشید. اگر سعی کنید این کار را انجام دهید، یک متغیر جدید با همین نام، اما محلی برای این تابع ایجاد خواهید کرد.

$per="Dima"; function primer() // انجام می دهد: نمایش یک متغیر محلی ( echo "My name is ".$per; ) echo primer();

در این صورت عبارت My name is بر روی صفحه ظاهر می شود. این بدان معنی است که متغیر $per در داخل تابع primer ایجاد شده است و به طور پیش فرض یک مقدار صفر به آن اختصاص داده شده است. به منظور جلوگیری از چنین موانعی، باید از اپراتور استفاده کنید جهانی. بیایید کد بالا را بر این اساس اصلاح کنیم:

$per="Dima"; function primer() // انجام می دهد: نمایش یک متغیر سراسری ( global $per; echo "My name is ".$per; ) echo primer();

اکنون همه چیز باید خوب باشد - مشکل حل شده است. فقط فراموش نکنید که اگر یک تابع مقدار یک متغیر خارجی را تغییر دهد، چنین تغییری بر کل برنامه تأثیر می گذارد، بنابراین باید با دقت از این عملگر استفاده کنید!

توابع دو یا چند آرگومان

برخی از آرگومان‌های ارسال شده به یک تابع را می‌توان اختیاری کرد و باعث می‌شود که تابع کمتر درخواست کند. مثال زیر این موضوع را به وضوح نشان می دهد:

… فونت تابع ($text، $size=5) // انجام: اندازه فونت خروجی (echo " ".$text.""; ) font("سلام
",1)؛ font("سلام
",2)؛ font("سلام
",3)؛ font("سلام
",4)؛ font("سلام
",5)؛ font("سلام
",6)؛ font("سلام
");

به طور پیش فرض اندازه فونت 5 است. اگر پارامتر دوم تابع را حذف کنیم، برابر با این مقدار خواهد بود.

نتیجه

قبل از خداحافظی، می خواهم توجه شما را به یک توصیه جلب کنم. این شامل قرار دادن تمام توابعی است که نوشته اید در یک فایل (به عنوان مثال function.php). و سپس، در فایلی که باید تابع را فراخوانی کنید، فقط باید function.php را وارد کنید و همه چیز برای استفاده آماده خواهد بود. این کار درک منطق برنامه شما را بسیار آسان تر می کند. برای اتصال از:

include_once("function.php");

require_once("function.php");

اگر ماهیت موضوع مورد بحث در این مقاله را درک می کنید، مطمئن هستم که می توانید به راحتی از توابع در برنامه های خود استفاده کنید. یک بار دیگر، این کار باعث می‌شود که آنها سازگارتر و قابل استفاده‌تر شوند.

این سومین مقاله از مجموعه «تئوری دسته‌بندی برای برنامه‌نویسان» است.

چه کسی به انواع نیاز دارد؟

در مورد مزایای تایپ استاتیک در مقابل پویا و تایپ قوی در مقابل ضعیف در جامعه اختلاف نظر وجود دارد. اجازه دهید انتخاب تایپ را با یک آزمایش فکری توضیح دهم. میلیون ها میمون را با صفحه کلید تصور کنید که با خوشحالی کلیدهای تصادفی را فشار می دهند، برنامه ها را می نویسند، کامپایل می کنند و اجرا می کنند.

با زبان ماشین، هر ترکیبی از بایت های تولید شده توسط میمون ها پذیرفته و اجرا می شود. اما در زبان های سطح بالا، بسیار ارزشمند است که کامپایلر قادر به تشخیص خطاهای واژگانی و دستوری باشد. بسیاری از برنامه ها به سادگی رد می شوند و میمون ها بدون موز می مانند، اما بقیه شانس بیشتری برای معنی دار شدن خواهند داشت. بررسی نوع مانع دیگری در برابر برنامه های بی معنی ایجاد می کند. علاوه بر این، در حالی که در زبان‌های تایپ شده پویا، عدم تطابق نوع فقط در زمان اجرا شناسایی می‌شود، در زبان‌هایی که به‌صورت ایستا بررسی می‌شوند، ناهماهنگی‌های نوع در زمان کامپایل شناسایی می‌شوند، که بسیاری از برنامه‌های نادرست را قبل از اینکه فرصتی برای اجرا داشته باشند، از بین می‌برد.

بنابراین سؤال این است که آیا می‌خواهیم میمون‌ها شاد باشند یا برنامه‌های درستی ایجاد کنند؟
(یادداشت مترجم: نیازی به توهین نیست، نویسنده فقط استعاره های خسته کننده کمتری را نسبت به RNG و "توالی های تصادفی بایت" دوست دارد و برنامه نویسان را میمون نمی نامد).

به طور معمول، هدف از آزمایش فکری میمون تایپ، خلق آثار کامل شکسپیر است (یادداشت مترجم: یا جنگ و صلح تولستوی). بررسی املا و دستور زبان در یک حلقه به طور چشمگیری شانس موفقیت شما را افزایش می دهد. آنالوگ بررسی نوع از این هم فراتر می رود: پس از اینکه رومئو انسان اعلام شد، بررسی نوع اطمینان حاصل می کند که او برگ نمی روید و با میدان گرانشی قدرتمند خود فوتون نمی گیرد.

انواع برای ترکیب پذیری مورد نیاز است

نظریه مقوله ترکیبات فلش ها را مطالعه می کند. فقط هر دو فلش را نمی توان با هم ترکیب کرد: شی هدف یک فلش باید با شی مبدا فلش بعدی مطابقت داشته باشد. در برنامه نویسی، ما نتایج را از یک تابع به تابع دیگر منتقل می کنیم. اگر تابع دوم نتواند داده های به دست آمده توسط تابع اول را به درستی تفسیر کند، برنامه کار نخواهد کرد. هر دو تابع باید با هم تناسب داشته باشند تا ترکیب آنها کار کند. هرچه سیستم نوع زبان قوی‌تر باشد، این تناسب بهتر می‌تواند توصیف و به طور خودکار تأیید شود.

تنها استدلال جدی که من علیه تایپ استاتیک قوی می شنوم این است که ممکن است برخی از برنامه هایی که از نظر معنایی درست هستند را رد کند. در عمل این اتفاق بسیار نادر است (یادداشت مترجم: برای جلوگیری از سردرگمی، توجه می کنم که نویسنده به این نکته توجه نکرده یا موافق نیست که سبک های زیادی وجود دارد، و تایپ اردک که برای برنامه نویسان در زبان های برنامه نویسی آشناست، نیز حق حیات دارد. از سوی دیگر، تایپ اردک در سیستم نوع دقیق از طریق الگوها، صفات، کلاس‌های نوع، رابط‌ها امکان‌پذیر است، فناوری‌های زیادی وجود دارد، بنابراین نظر نویسنده را نمی‌توان کاملاً نادرست در نظر گرفت.)و در هر صورت، هر زبانی حاوی نوعی درب پشتی برای دور زدن سیستم نوع در مواقع ضروری است. حتی Haskell دارای اجبار ناامن است. اما از چنین طرح هایی باید عاقلانه استفاده کرد. گرگور سامسا، شخصیت فرانتس کافکا، زمانی که به یک سوسک غول پیکر تبدیل می شود، سیستم نوع را در هم می شکند، و همه ما می دانیم که پایان آن چگونه است. (یادداشت مترجم: بد:).

بحث دیگری که اغلب می شنوم این است که تایپ قوی بار زیادی را بر دوش برنامه نویس می گذارد. من می‌توانم با این مشکل همدردی کنم، چون خودم چندین اعلان تکرارکننده را در C++ نوشته‌ام، با این تفاوت که یک فناوری وجود دارد، استنتاج نوع، که به کامپایلر اجازه می‌دهد بیشتر انواع را از زمینه‌ای که در آن استفاده می‌شود، استنتاج کند. در C++، می توانید یک متغیر خودکار را اعلام کنید و کامپایلر نوع آن را برای شما استنباط می کند.

در Haskell، به جز در موارد نادر، حاشیه نویسی نوع اختیاری است. برنامه نویسان تمایل دارند به هر حال از آنها استفاده کنند زیرا انواع می توانند چیزهای زیادی در مورد معنای کد شما به شما بگویند و اعلان های نوع به شما در درک خطاهای کامپایل کمک می کند. یک روش معمول در هاسکل شروع یک پروژه با توسعه انواع است. بعداً، حاشیه‌نویسی‌های تایپ اساس پیاده‌سازی را تشکیل می‌دهند و به نظرات تضمین‌شده توسط کامپایلر تبدیل می‌شوند.

تایپ استاتیک قوی اغلب به عنوان بهانه ای برای آزمایش نکردن کد استفاده می شود. گاهی اوقات می شنوید که برنامه نویسان Haskell می گویند: "اگر کد ساخته شود، درست است." البته هیچ تضمینی وجود ندارد که برنامه ای که از نوع صحیح است به معنای تولید نتیجه صحیح باشد. به عنوان یک نتیجه از این نگرش، در تعدادی از مطالعات Haskell به طور قابل توجهی از زبان های دیگر در کیفیت کد، آنطور که ممکن است انتظار داشت، بهتر عمل نکرد. به نظر می رسد در یک محیط تجاری نیاز به رفع اشکالات فقط تا سطح خاصی از کیفیت وجود دارد که بیشتر به اقتصاد توسعه نرم افزار و تحمل کاربر نهایی مربوط می شود و ارتباط بسیار کمی با زبان برنامه نویسی یا توسعه دارد. روش شناسی یک معیار بهتر اندازه گیری تعداد پروژه هایی است که از برنامه عقب مانده یا با عملکرد بسیار کاهش یافته تحویل داده شده اند.

حال با توجه به این ادعا که تست واحد می تواند جایگزین تایپ قوی شود. بیایید به یک روش متداول refactoring در زبان‌های با تایپ قوی نگاه کنیم: تغییر نوع آرگومان به تابع. در زبان های قوی تایپ شده کافی است اعلان این تابع را تغییر دهید و سپس خطاهای ساخت را برطرف کنید. در زبان‌های با تایپ ضعیف، این واقعیت که یک تابع اکنون در انتظار داده‌های دیگری است را نمی‌توان به تماس‌گیرنده نسبت داد.

آزمایش واحد ممکن است برخی از ناسازگاری ها را پیدا کند، اما آزمایش تقریباً همیشه یک فرآیند احتمالی است تا قطعی. (یادداشت مترجم: شاید منظور آنها مجموعه‌ای از آزمایش‌ها بوده است: شما همه ورودی‌های ممکن را پوشش نمی‌دهید، بلکه یک نمونه معین خاص را پوشش می‌دهید.)تست یک جایگزین ضعیف برای اثبات صحت است.

انواع چیست؟

ساده ترین توصیف انواع این است که آنها مجموعه ای از مقادیر هستند. نوع Bool (به یاد داشته باشید، انواع بتن با حروف بزرگ در Haskell شروع می شود) با مجموعه ای از دو عنصر مطابقت دارد: True و False. نوع Char مجموعه ای از تمام کاراکترهای یونیکد است، مانند "a" یا "ą".

مجموعه ها می توانند متناهی یا بی نهایت باشند. نوع String که در اصل مترادف لیست Char است، نمونه ای از مجموعه بی نهایت است.

وقتی x را به عنوان یک عدد صحیح اعلام می کنیم:
x:: عدد صحیح
می گوییم عنصری از مجموعه اعداد صحیح است. عدد صحیح در Haskell یک مجموعه نامتناهی است و می تواند برای محاسبات با هر دقتی استفاده شود. همچنین مجموعه محدودی از Int وجود دارد که مربوط به یک نوع ماشین است، مانند int در C++.

نکات ظریفی وجود دارد که معادل سازی انواع با ست ها را دشوار می کند. مشکلاتی در مورد توابع چند شکلی وجود دارد که دارای تعاریف چرخه‌ای هستند و همچنین با این واقعیت که نمی‌توانید مجموعه‌ای از همه مجموعه‌ها را داشته باشید. اما، همانطور که قول داده بودم، یک ریاضیدان سختگیر نخواهم بود. مهم این است که یک دسته از مجموعه ها به نام Set وجود دارد و ما با آن کار خواهیم کرد.
در مجموعه، اشیا مجموعه‌ها و مورفیسم‌ها (فلش‌ها) توابع هستند.

مجموعه مقوله خاصی است زیرا می توانیم درون اشیاء آن را نگاه کنیم و این به ما کمک می کند تا به طور شهودی چیزهای زیادی را درک کنیم. به عنوان مثال، می دانیم که مجموعه خالی هیچ عنصری ندارد. می دانیم که مجموعه های خاصی از یک عنصر وجود دارد. می دانیم که توابع عناصر یک مجموعه را به عناصر مجموعه دیگر نگاشت می کنند. آنها می توانند دو عنصر را به یک نگاشت کنند، اما نه یک عنصر را به دو. می دانیم که تابع هویت هر عنصر مجموعه را به خودش نگاشت می کند و غیره. من قصد دارم به تدریج همه این اطلاعات را فراموش کنم و در عوض همه این مفاهیم را به صورت کاملاً طبقه بندی شده، یعنی در قالب اشیا و فلش بیان کنم.

در یک دنیای ایده‌آل، به سادگی می‌توان گفت که انواع در Haskell مجموعه‌ها هستند و توابع در Haskell توابع ریاضی در بین آن‌ها هستند. فقط یک مشکل کوچک وجود دارد: تابع ریاضی هیچ کدی را اجرا نمی کند - فقط جواب را می داند. یک تابع در Haskell باید پاسخ را محاسبه کند. اگر بتوان پاسخ را در تعداد محدودی از مراحل، هر چقدر هم که بزرگ باشد، به دست آورد، مشکلی نیست. اما برخی از محاسبات وجود دارد که شامل بازگشت هستند و ممکن است هرگز کامل نشوند. ما نمی توانیم به سادگی توابع غیر پایانی را در Haskell غیرممکن کنیم، زیرا تشخیص اینکه آیا یک تابع خاتمه می یابد یا خیر - مشکل معروف توقف - غیر قابل حل است. به همین دلیل است که دانشمندان کامپیوتر یک ایده درخشان یا هک کثیف بسته به دیدگاه شما ارائه کردند تا هر نوع را با مقدار خاصی به نام پایین گسترش دهند. (یادداشت مترجم: این اصطلاح (پایین) در روسی تا حدی احمقانه به نظر می رسد، اگر کسی گزینه خوبی می داند، لطفاً پیشنهاد دهد.)، که با _|_ یا در یونیکد ⊥ نشان داده می شود. این "مقدار" مربوط به یک محاسبه ناقص است. بنابراین یک تابع به صورت زیر اعلام شده است:
f::Bool -> Bool
ممکن است True، False یا _|_ را برگرداند. دومی به این معنی است که تابع هرگز کامل نمی شود.

جالب است که وقتی پایین را در سیستم type قبول کردید، راحت است که هر خطای زمان اجرا را به عنوان پایین در نظر بگیرید، و حتی به یک تابع اجازه دهید به طور صریح پایین را برگرداند. دومی معمولاً با استفاده از عبارت تعریف نشده انجام می شود:
f::Bool -> Bool f x = تعریف نشده
این تعریف از بررسی نوع عبور می کند زیرا تعریف نشده به پایین ارزیابی می شود که در همه انواع از جمله Bool گنجانده شده است. حتی می توانید بنویسید:
f::Bool -> Bool f = تعریف نشده
(بدون x) زیرا bottom نیز عضوی از نوع Bool -> Bool است.

توابعی که می‌توانند پایین را برگردانند جزئی نامیده می‌شوند، برخلاف توابع معمولی که نتایج معتبر را برای همه آرگومان‌های ممکن برمی‌گردانند.

به دلیل پایین بودن، دسته انواع و توابع Haskell Hask نامیده می شود، نه Set. از نقطه نظر تئوری، این منبع عوارض بی پایان است، بنابراین در این مرحله من از چاقوی قصابی خود استفاده می کنم و آن را یک روز می نامم. از نقطه نظر عملگرایانه، می توان توابع غیر پایانی و پایین را نادیده گرفت و هاسک را به عنوان یک مجموعه تمام عیار در نظر گرفت.

چرا به یک مدل ریاضی نیاز داریم؟

به عنوان یک برنامه نویس، شما با نحو و گرامر یک زبان برنامه نویسی آشنا هستید. این جنبه های زبان معمولاً در همان ابتدای مشخصات زبان به طور رسمی توصیف می شوند. اما توصیف معنا و معناشناسی زبان بسیار دشوارتر است. این توضیحات صفحات بسیار بیشتری را اشغال می کند، به ندرت به اندازه کافی رسمی است و تقریباً هرگز کامل نمی شود. از این رو بحث‌های بی‌پایان میان حقوقدانان زبان و کل صنعت کلبه کتاب‌هایی که به تفسیر پیچیدگی‌های استانداردهای زبان اختصاص داده شده است.

ابزارهای رسمی برای توصیف معنایی یک زبان وجود دارد، اما به دلیل پیچیدگی آنها، بیشتر برای زبان های ساده و آکادمیک استفاده می شود تا غول های واقعی برنامه نویسی صنعتی. یکی از این ابزارها معناشناسی عملیاتی نام دارد و مکانیک اجرای برنامه را توصیف می کند. این یک مفسر رسمی و ایده آل را تعریف می کند. معناشناسی زبان‌های صنعتی مانند C++ معمولاً با استفاده از استدلال غیررسمی، اغلب در قالب یک «ماشین انتزاعی» توصیف می‌شود.

مشکل این است که اثبات چیزی در مورد برنامه هایی که از معنای عملیاتی استفاده می کنند بسیار دشوار است. برای نشان دادن ویژگی یک برنامه، اساساً باید آن را از طریق یک مترجم ایده آل "اجرا کنید".

مهم نیست که برنامه نویسان هرگز صحت را به طور رسمی اثبات نمی کنند. ما همیشه "فکر می کنیم" که داریم برنامه های درستی می نویسیم. هیچ کس پشت صفحه کلید نمی نشیند و می گوید: "اوه، من فقط چند خط کد می نویسم و ​​ببینم چه می شود." (یادداشت مترجم: آه، اگر فقط...)ما معتقدیم که کدی که می نویسیم اقدامات خاصی را انجام می دهد که نتایج مورد نظر را ایجاد می کند. اگر اینطور نباشد، معمولاً بسیار شگفت زده می شویم. این بدان معنی است که ما در واقع به برنامه هایی که می نویسیم فکر می کنیم و معمولاً این کار را با اجرای یک مترجم در سرمان انجام می دهیم. فقط، پیگیری همه متغیرها بسیار دشوار است. کامپیوترها در اجرای برنامه ها خوب هستند، مردم نه! اگر ما بودیم نیازی به کامپیوتر نداشتیم.

اما یک جایگزین وجود دارد. به آن معناشناسی دلالتی می گویند و بر پایه ریاضیات است. در معناشناسی معنایی، یک تفسیر ریاضی برای هر ساختار زبانی توصیف می شود. بنابراین، اگر می خواهید ویژگی یک برنامه را اثبات کنید، به سادگی یک قضیه ریاضی را اثبات می کنید. شما فکر می کنید که اثبات قضایا مشکل است، اما در واقع، ما انسان ها هزاران سال است که روش های ریاضی می سازیم، بنابراین دانش انباشته زیادی وجود دارد که می توان از آنها استفاده کرد. همچنین، در مقایسه با قضایایی که ریاضی‌دانان حرفه‌ای ثابت می‌کنند، مشکلاتی که در برنامه‌نویسی با آن‌ها مواجه می‌شویم، اگر نگوییم بی‌اهمیت، بسیار ساده هستند. (یادداشت مترجم: برای اثبات، نویسنده در صدد توهین به برنامه نویسان نیست.)

تعریف تابع فاکتوریل را در هسکل در نظر بگیرید، زبانی که به راحتی خود را به معناشناسی دلالتی می رساند:
واقعیت n = محصول
عبارت لیستی از اعداد صحیح از 1 تا n است. تابع محصول تمام عناصر یک لیست را ضرب می کند. دقیقا مثل تعریف فاکتوریل برگرفته از کتاب درسی. این را با C مقایسه کنید:
int fact(int n) (int i؛ int نتیجه = 1؛ برای (i = 2؛ i<= n; ++i) result *= i; return result; }
باید ادامه بدم؟ (یادداشت مترجم: نویسنده با گرفتن یک تابع کتابخانه در Haskell کمی تقلب کرده است. در واقع، نیازی به تقلب نبود؛ توصیف صادقانه، طبق تعریف، دشوارتر از این نیست):
واقعیت 0 = 1 واقعیت n = n * واقعیت (n - 1)
خوب، من فوراً اعتراف می کنم که یک شات ارزان بود! فاکتوریل یک تعریف ریاضی واضح دارد. خواننده زیرک ممکن است بپرسد: مدل ریاضی برای خواندن یک کاراکتر از صفحه کلید یا ارسال یک بسته از طریق شبکه چیست؟ برای مدت طولانی، این یک سوال ناخوشایند است که منجر به توضیحات نسبتاً گیج کننده می شود. به نظر می‌رسد که معناشناسی دلالتی برای تعداد قابل توجهی از مسائل مهمی که برای نوشتن برنامه‌های مفید ضروری بودند و می‌توان آن‌ها را به راحتی با معناشناسی عملیاتی حل کرد، نامناسب باشد. این پیشرفت از نظریه مقوله حاصل شد. Eugenio Moggi کشف کرد که اثرات محاسباتی را می توان به موناد تبدیل کرد. این مشاهدات مهمی بود که نه تنها به معنای معنایی معنایی جان تازه‌ای بخشید و برنامه‌های صرفاً کاربردی را راحت‌تر کرد، بلکه اطلاعات جدیدی در مورد برنامه‌نویسی سنتی ارائه کرد. بعداً وقتی ابزارهای طبقه بندی بیشتری را توسعه دادیم، در مورد مونادها صحبت خواهم کرد.

یکی از مزایای مهم داشتن یک مدل ریاضی برای برنامه نویسی، امکان اثبات صحت نرم افزار است. این ممکن است زمانی که شما در حال نوشتن نرم افزار مصرف کننده هستید چندان مهم به نظر نرسد، اما مناطقی از برنامه نویسی وجود دارد که هزینه شکست می تواند بسیار زیاد باشد، یا زندگی انسان در معرض خطر است. اما حتی هنگام نوشتن برنامه‌های کاربردی وب برای سیستم مراقبت‌های بهداشتی، می‌توانید از این ایده که توابع و الگوریتم‌های کتابخانه استاندارد Haskell همراه با اثبات صحت کامل هستند، قدردانی کنید.

عملکردهای تمیز و کثیف

آنچه ما توابع را در C++ یا هر زبان دستوری دیگری می نامیم با آنچه ریاضیدانان توابع می نامند یکسان نیست. یک تابع ریاضی صرفاً یک نگاشت از مقادیر به مقادیر است.

ما می توانیم یک تابع ریاضی را در یک زبان برنامه نویسی پیاده سازی کنیم: چنین تابعی، با توجه به یک مقدار ورودی، مقدار خروجی را محاسبه می کند. تابعی که یک عدد را مربع می کند احتمالاً مقدار ورودی را در خودش ضرب می کند. هر بار که فراخوانی شود این کار را انجام می دهد و هر بار که با همان آرگومان فراخوانی می شود، تضمین می شود که همان نتیجه را ایجاد کند. مربع عدد با فازهای ماه تغییر نمی کند.

علاوه بر این، محاسبه مربع یک عدد نباید عارضه ای برای دادن غذای خوشمزه به سگ شما داشته باشد. "تابع" که این کار را انجام می دهد را نمی توان به راحتی با یک تابع ریاضی مدل کرد.

در زبان های برنامه نویسی، توابعی که همیشه نتیجه یکسانی را بر روی آرگومان های یکسان ایجاد می کنند و عوارض جانبی ندارند، خالص نامیده می شوند. در زبان تابعی خالص مانند Haskell، همه توابع خالص هستند. این امر تعیین معنای معنایی این زبان‌ها و مدل‌سازی آن‌ها را با استفاده از نظریه دسته‌بندی آسان‌تر می‌کند. برای زبان های دیگر، همیشه می توانید خود را به یک زیرمجموعه خالص محدود کنید، یا به طور جداگانه به عوارض جانبی فکر کنید. بعداً خواهیم دید که چگونه مونادها به ما اجازه می‌دهند تا انواع افکت‌ها را تنها با استفاده از توابع خالص مدل‌سازی کنیم. در نتیجه، با محدود کردن خود به توابع ریاضی چیزی از دست نمی دهیم.

نمونه هایی از انواع

هنگامی که تصمیم گرفتید که انواع مجموعه هستند، می توانید نمونه های بسیار عجیب و غریبی بیاورید. به عنوان مثال، چه نوع مربوط به مجموعه خالی است؟ خیر، در C++ باطل نیست، اگرچه در Haskell به این نوع Void می گویند. این نوعی است که با هیچ مقداری پر نمی شود. شما می توانید تابعی را تعریف کنید که یک Void بگیرد، اما هرگز نمی توانید آن را فراخوانی کنید. برای فراخوانی آن، باید مقداری از نوع Void ارائه کنید، و به سادگی وجود ندارد. در مورد آنچه که این تابع می تواند برگرداند، هیچ محدودیتی وجود ندارد. می تواند هر نوع را برگرداند (اگرچه این اتفاق هرگز نمی افتد زیرا نمی توان آن را فراخوانی کرد). به عبارت دیگر تابعی است که در نوع برگشتی خود چند شکلی است. هاسکلرها آن را می نامیدند:
پوچ::باطل -> a
(یادداشت مترجم: تعریف چنین تابعی در C++ غیرممکن است: در C++ هر نوع حداقل یک مقدار دارد.)

(به یاد داشته باشید که a یک متغیر نوع است که می تواند هر نوع باشد.) این نام تصادفی نیست. تفسیر عمیق تری از انواع و توابع بر حسب منطق وجود دارد که هم ریختی کری هاوارد نامیده می شود. نوع Void نشان دهنده نادرستی است، و تابع پوچ بیانگر این ادعا است که چیزی از نادرستی ناشی می شود، مانند عبارت لاتین "ex falso sequitur quodlibet". (یادداشت مترجم: هر چیزی از نادرستی ناشی می شود.)

در مرحله بعد، نوع مربوط به مجموعه تک تنه می آید. این نوعی است که فقط یک مقدار ممکن دارد. این معنی به سادگی «وجود دارد» است. ممکن است فوراً آن را تشخیص ندهید، اما در C++ باطل است. در مورد توابع از و به این نوع فکر کنید. یک تابع void همیشه می تواند فراخوانی شود. اگر یک تابع خالص باشد، همیشه همان نتیجه را برمی‌گرداند. در اینجا مثالی از چنین تابعی آورده شده است:
int f44() (بازگشت 44;)
ممکن است فکر کنید که این تابع "هیچ چیز" را می پذیرد، اما همانطور که دیدیم، تابعی که "هیچ چیز" را می پذیرد نمی تواند فراخوانی شود زیرا هیچ مقداری وجود ندارد که نشان دهنده نوع "هیچ چیز" باشد. پس این تابع چه چیزی را می پذیرد؟ از نظر مفهومی، یک مقدار ساختگی می گیرد که فقط یک نمونه دارد، بنابراین نیازی نیست که آن را به صراحت در کد مشخص کنیم. اما هاسکل برای این معنی نمادی دارد: جفت پرانتز خالی (). بنابراین، به دلیل یک تصادف خنده دار (یا نه تصادفی؟)، فراخوانی یک تابع از void در هر دو C++ و Haskell یکسان به نظر می رسد. علاوه بر این، به دلیل علاقه هسکل به مختصر بودن، از همان نماد () برای نوع، سازنده و مقدار واحد مربوط به مجموعه تک‌تن استفاده می‌شود. این تابع در Haskell است:
f44::() -> عدد صحیح f44() = 44
خط اول اعلام می کند که f44 نوع () به نام "unit" را به نوع Integer تبدیل می کند. خط دوم مشخص می کند که f44 از تطبیق الگو برای تبدیل تنها سازنده یک، یعنی () به عدد 44 استفاده می کند. شما این تابع را با ارائه مقدار () فراخوانی می کنید:
f44()
توجه داشته باشید که هر تابع از یک معادل انتخاب یک عنصر از نوع هدف است (در اینجا عدد صحیح 44 انتخاب شده است). در واقع می توانید f44 را به عنوان نمایش دیگری از عدد 44 در نظر بگیرید. این مثالی است از اینکه چگونه می توانیم ارجاع مستقیم به عناصر یک مجموعه را با یک تابع (یک فلش) جایگزین کنیم. توابع از یک به یک نوع خاص A مطابقت یک به یک با عناصر مجموعه A دارند.

در مورد توابعی که void برمی‌گردانند، یا در Haskell، یک را برمی‌گردانند چطور؟ در C++ از چنین توابعی برای عوارض جانبی استفاده می شود، اما می دانیم که چنین توابعی به معنای ریاضی کلمه، توابع واقعی نیستند. یک تابع خالص که یک را برمی گرداند هیچ کاری انجام نمی دهد: آرگومان خود را کنار می گذارد.

از نظر ریاضی، تابعی از مجموعه A تا مجموعه تک تن، هر عنصر را به یک عنصر از آن مجموعه نگاشت می کند. برای هر A دقیقاً یک تابع وجود دارد. در اینجا برای عدد صحیح است:
fInt::Integer -> () fInt x = ()
شما هر عدد صحیحی به آن می دهید و یک عدد را برمی گرداند. به منظور اختصار، هاسکل استفاده از خط زیر را به عنوان استدلال مجاز می‌داند که کنار گذاشته می‌شود. به این ترتیب دیگر نیازی به تعیین نام برای آن نیست. کد بالا را می توان به صورت زیر بازنویسی کرد:
fInt::عدد صحیح -> () fInt_ = ()
توجه داشته باشید که اجرای این تابع نه تنها مستقل از مقدار ارسال شده به آن، بلکه مستقل از نوع آرگومان نیز می باشد.

توابعی را که می توان با فرمول یکسان برای هر نوع تعریف کرد، از نظر پارامتری چند شکلی نامیده می شود. شما می توانید یک خانواده کامل از این توابع را با یک معادله، با استفاده از یک پارامتر به جای یک نوع خاص، پیاده سازی کنید. چگونه یک تابع چند شکلی را از هر نوع به یک فراخوانی کنیم؟ البته ما آن را واحد می نامیم:
واحد::a -> () واحد _ = ()
در C++ شما آن را به صورت زیر پیاده سازی می کنید:
قالب واحد خالی (T) ()
(یادداشت مترجم: برای کمک به کامپایلر در بهینه سازی آن در noop، بهتر است اینگونه باشد):
قالب واحد خالی (T&&) ()
بعدی در "نوع شناسی انواع" مجموعه ای از دو عنصر است. در C++ آن را bool و در Haskell جای تعجب نیست که Bool نامیده می شود. تفاوت این است که در C++ bool یک نوع داخلی است، در حالی که در Haskell می توان آن را اینگونه تعریف کرد:
داده Bool = True | نادرست
(این تعریف باید به این صورت خوانده شود: Bool می تواند True یا False باشد.) در اصل، می توان این نوع را در C++ توصیف کرد:
enum bool(درست، نادرست)؛
اما C++ enum در واقع یک عدد صحیح است. می‌توان از C++11 «class enum» استفاده کرد، اما پس از آن باید مقدار را با نام کلاس: bool::true یا bool::false تعیین کرد، نه اینکه نیاز به گنجاندن هدر مربوطه در هر فایل را ذکر کنیم. که از آن استفاده می کند.

توابع Pure Bool به سادگی دو مقدار را از نوع هدف انتخاب می کنند، یکی مربوط به True و دیگری مربوط به False.

توابع در Bool را محمول می گویند. به عنوان مثال، کتابخانه Data.Char در Haskell حاوی محمولات زیادی است، مانند IsAlpha یا isDigit. یک کتابخانه مشابه در C++ وجود دارد ، که در میان چیزهای دیگر، توابع isalpha و isdigit را اعلام می کند، اما آنها به جای یک مقدار بولی، یک int برمی گردانند. محمول های فعلی در تعریف می شوند و به آنها ctype::is(alpha, c) و ctype::is(digit, c) می گویند.



 


خواندن:



زبان برنامه نویسی تایپ شده مشخص کننده های نوع یا قالب یا کاراکترهای تبدیل یا کاراکترهای کنترلی

زبان برنامه نویسی تایپ شده مشخص کننده های نوع یا قالب یا کاراکترهای تبدیل یا کاراکترهای کنترلی

زبان برنامه نویسی C++ آخرین به روز رسانی: 2017/08/28 زبان برنامه نویسی C++ یک زبان کامپایل شده سطح بالا است...

برنامه کاری پست روسیه در تعطیلات سال نو کار پستی در تعطیلات سال نو

برنامه کاری پست روسیه در تعطیلات سال نو کار پستی در تعطیلات سال نو

پست روسیه در قرن بیست و یکم به یک موسسه جهانی تبدیل شده است که نه تنها به دریافت نامه ها و بسته ها کمک می کند. پرداخت آب و برق، حقوق بازنشستگی و ...

Tass: رمزگشایی مخفف

Tass: رمزگشایی مخفف

این اصطلاح از اختصار ایتالیایی و brevis لاتین - کوتاه آمده است. در کتب و نسخه های خطی باستانی این نام مخفف ...

قالب های گواهی خالی دانلود قالب گواهی افتخار برای چاپ

قالب های گواهی خالی دانلود قالب گواهی افتخار برای چاپ

با سلام، خواننده عزیز! امروز به شما خواهم گفت که چگونه در Word یک نامه بسازید. در کارم مجبور شدم تعداد زیادی از...

فید-تصویر RSS