نوشته های روزبه شریف نسب



برای یک مسابقه برنامه‌نویسی یک سوال ساده طرح کردم که به راحتی قابل حل باشه ولی یک شرط مهم برا حل گذاشتم، برای حل تنها مجاز به استفاده از زبان Haskell هستید. اما چرا هسکل مهمه و چرا همچین تصمیمی گرفتم؟ در ادامه متوجه می‌شوید.

این روزها هرکس بخواهد برنامه‌نویسی را شروع کند، بین زبان‌های پایتون و سی و یا جاوا‌اسکریپت یا نهایتا جاوا و سی‌پلاس‌پلاس انتخاب می‌کند و برنامه‌نویسی رویه‌ای (procedural) و در ادامه شی‌گرا (Object Oriented) را یاد می‌گیرد و احتمالا در ادامه هم در همین بخش ادامه می‌دهد و فریم‌ورک‌های جدید و .

اما برنامه‌نویسی فانکشنال (functional programming یا FP) مورد غفلت واقع شده اما برنامه‌نویسی فانکشنال چی هست؟ به طور خلاصه یک پارادایم برنامه‌نویسی در مقابل برنامه‌نویسی رویه‌ای و شی‌گراست.

با توجه به قدمت برنامه‌نویسی رویه‌ای‌، زبان‌های‌ برنامه‌نویسی رویه‌ای زبان‌های پرقدمتی مثل FORTRAN و BASIC و C و COBOL هستند. این دسته از زبان‌ها متکی به صدا زدن procedure (روتین یا فانشکن) هستند که هر روتین مجموعه‌ای از دستورات است. در واقع کدها در قالب routine ها نوشته می‌شوند.

از بزرگان برنامه‌نویسی شی‌گرا می‌شود به جاوا و سی‌پلاس‌پلاس، سی‌شارپ و جاوا‌اسکریپت و اشاره کرد که مفاهیم برنامه‌نویسی شی‌گرا مثل ابجکت‌، کلاس‌، پنهان‌سازی(encapsulation)، وراثت(inheritance) و چندریختی(polymorphism) را پشتیبانی می‌کنند. در این پارادایم، کدها در غالب متد‌هایی برای اشیا نوشته می‌شوند و قابل فراخوانی روی هر شی (یا در مواردی روی کلاس) هستند.

اما زبان‌های فانکنشال مثل Haskell و #F و Erlang و elixir و Clojure روش فکری متفاوتی دارند! در این زبان‌ها کد‌ها در قالب فانکشن‌ها نوشته می‌شوند (مثل برنامه‌نویسی رویه‌ای؟) اما فانکشن‌ها شهروندان درجه‌اول در زبان هستند یعنی کار کردن با آن‌ها به راحتی کار کردن با متغیرهاست و امکان pass شدن و ترکیب شدن و را دارند.

توجه: مثال‌هایی که زده شد دقیق نیستند چون اکثر زبان‌ها چند پارادایمی هستند و نمی‌توان گفت سی فقط رویه‌ای است چون با پوینتر به فانکشن قابلیت‌های فانکشنال را هم تا حدی میسر کرده است و یا مثلا جاوا در نسخه 8 امکانات برنامه‌نویسی فانکشنال را تا حدی میسر کرده است.

ریشه و پایه‌ی زبان‌های فانکشنال، ‌lambda calculus است که ایده‌ی نوشتن function و حل مساله به روش بازگشتی را پایه گذاشت.

اما مفاهیمی که در زبان‌های فانکشنال با آن‌ها سرو کار داریم چه چیز‌هایی هستند؟

۱- فانکشن‌های مرتبه بالا‌(higher order function)‌ فانکشنی که یک یا چند فانکنش به عنوان ورودی بگیرد و فانکشن به عنوان خروجی بدهد، مثل انتگرال!

۲- فانکشن‌های خالص(pure function): تابع pure تابعیست که خروجی‌اش دقیقا از روی ورودی‌هایش ساخته می‌شود (مثل همه‌ی توابع ریاضی)، یعنی این تابع با بیرون از تابع و بقیه‌ی دنیا (به جز از طریق ورودی‌ها) هیچ ارتباطی ندارد و هیچ اثری هم روی بیرون از تابع (بقیه دنیا) نمی‌گذارد به جز محاسبه‌ی خروجی! به طور عملی‌تر هیچ متفیر گلوبالی وجود ندارد، کار با IO و تعامل با کاربر و هرگونه side-effectی وجود ندارد.

۳- توابع بازگشتی (recursive functions): توابعی که برای حل یک مساله، از حل زیر مساله‌هایی با ابعاد کوچک‌تر کمک می‌گیرند (مشابه استدلال استقرایی که f(n) را فرض می‌کنیم و برای f(n+1) اثبات می‌کنیم) برای حل مساله با اندازه k از همان تابع برای ورودی با اندازه k-1 (یا به هر صورتی کوچک‌‌تر از k) کمک می‌گیرند و با استفاده از آن، مساله را برای ورودی با اندازه k حل می‌کنند. البته یک شرط پایه (مثل پایه استقرا) نیز وجود دارد که برای اندازه k=1 است که جواب بدیهی دارد.

کمی بیشتر در مورد برنامه‌نویسی شی‌گرا می‌توانید اینجا بخوانید.

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

هسکل یک زبان فانکشنال است (جزو مطرح‌ترین زبان‌های فانکشنال است) ولی نه یک زبان فانکشنال معمولی، یک زبان purely functional است.

هسکل statically typed است یعنی تایپ ها باید در زمان کامپایل معلوم باشند، این کار برای به حداقل رساندن خطا و اشتباه برنامه‌نویس است.

هسکل یک زبان تنبل (lazy) است. pure function ها به زبان امکان تنبلی (laziness) رو می‌دهند، تنبلی یعنی اینکه تا زمانی که واقعا به چیزی نیاز نداریم، برایش زمان و انرژی نگذاریم!

توی زبان برنامه‌نویسی به این معنیست که تا زمانی که به یک داده واقعا نیاز نیست، محاسبه نشود، این امر چطوری امکان‌پذیره؟ مقدار ها از توابع ساخته می‌شوند و توابع زبان هم همگی pure هستند پس تفاوتی ندارد که همان موقع که فراخوانی می‌شوند اجرا شوند و خروجی را آماده کنند یا هرموقع به خروجی‌شان واقعا نیاز بود!

این laziness امکانات عجیبی رو برای زبان (و بیش‌تر از زبان، برای برنامه‌نویس) فراهم می‌کند مثلا می‌توانیم یک لیست شامل همه‌ی اعداد طبیعی داشته باشیم. دقیقا مشخص است که این لیست شامل چه عددهاییست ولی مقدار تک تک‌شون دقیقا محاسبه نشده و هربار به هر مقداری نیاز داشته باشیم محاسبه می‌شود!

اما همه‌ی این تفاوت‌ها و تغییر در پارادایم به چه علتی؟

در زبان‌های فانشکنال به جای how to do به what to do پرداخته می‌شود یعنی برنامه‌ای که نوشته‌ می‌شود به جزییات اتفاقات سطح پایین کاری ندارد و صرفا تصریح می‌کند از برنامه چه انتظاری داریم! فرض کنید یک لیست از اعداد زوج می‌خواهیم، در زبان‌های رویه‌ای باید یک حلقه بزنیم و دقیقا بدانیم تا کجا به اعداد زوج احتیاج داریم و برای هر عدد،‌ در صورتی که زوج بود باید به آرایه یا list اضافه‌اش می‌کردیم اما در زبان فانکشنال کافیست بگوییم یک لیست اعداد طبیعی رو فیلتر کن، چه فیلتری؟ فیلتری که زوج‌ها رو برگرداند.

یا فرض کنید میخواهیم بررسی کنیم که یک عدد، اول هست یا نه، کافیه یه لیست از اعداد ۲ تا n-1 بسازیم و به هسکل بگوییم که بر هیچ کدام بخش‌پذیر نباشد، با یک خط کد امکان پذیر است!

این تفاوت‌ها (و احتمالا یه سری تفاوت که من اینجا نیاوردم و خودم بلد نبودم) برنامه‌‌های فانکشنال را گویا‌تر می‌کند، تغییر در کد را راحت‌تر امکان‌پذیر می‌سازد و کدها را کوتاه تر می‌کند.

یک خصوصیت خوب دیگر این زبان‌ها قدرتشان در همزمانی (concurrency) است که به خاطر ذات immutable بودن داده‌ها و مستقل بودن هر تابع از دیگر قسمت‌های برنامه میسر شده است.

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

برای شروع به کار با زبان هسکل ، می توانید از repl آنلاین آن در سایت رسمی خود هسکل استفاده کنید، البته کامپایلرهای انلاین هم در دسترس هستند.

کامپایلر خوب و شناخته‌شده‌ی هسکل، ghc است که در اکثر سیستم‌عامل ها قابل نصب و استفاده است.

همچنین در این لینک می‌توانید توضیحات دیگری را بخوانید.

آموزش‌های شروع به کار خوب هسکل هم موارد زیر است:

 

دو کتاب بسیار خوب هم پیدا کردم، یکی به زبان انگلیسی و قابلیت خواندن آنلاین و یکی به زبان فارسی (و البته گران قیمت!) که می‌توانید فصل‌های اولش را در این لینک بخوانید. (بسیار توصیه می‌شود)


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

زبان اولی که قصد معرفی دارم(و زبان محبوب خودم هست) زبان brainf*ck هست که اولین نکته‌ای که باید بدونید اینه که اسمش کاملا شایسته‌است و سعی نکنید باهاش برنامه‌نویسی کنید و از اون بدتر برنامه نویسی رو باهاش به کسی آموزش بدید.

یادگیریاین زبان بسیار ساده است ولی برنامه‌نویسی با اون بسیار سخته به این دلیل که کلا از ۸ تا کامند پشتیبانی می‌کنه و به جز اون‌ها هرچی در فایل برنامه باشه به عنوان کامنت در نظر گرفته می‌شه.

فکر می‌کنم این زبان مختصر ترین زبان Turing complete باشه و برای همینه که اینقدر معروف شده ولی در عمل کسی ازش استفاده نمی‌کنه :)

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

> = increases memory pointer, or moves the pointer to the right 1 block.
< = decreases memory pointer, or moves the pointer to the left 1 block.
+ = increases value stored at the block pointed to by the memory pointer
- = decreases value stored at the block pointed to by the memory pointer
[ = like c while(cur_block_value != 0) loop.
] = if block currently pointed to's value is not zero, jump back to [
, = like c getchar(). input 1 character.
. = like c putchar(). print 1 character to the console

توضیحات بیش‌تر را در این لینک مطالعه کنید

اما زبان چطوری کار می‌کند: در این زبان شما یک اشاره‌گر و یک حافظه نامحدود دارید که با دستور های < و > می توانید در خانه‌های حافظه جا به جا شوید، با دستور های + و − مقدار آن خانه حافظه یکی کم یا زیاد می‌شود و وظیفه چاپ و گرفتن اطلاعات از کاربر با "." و "," است.

احتمالا سخت ترین قسمت زبان for آن باشد(شاید هم while مناسب تر باشد) که با دستورات ] , [ کار می‌کند و دستورات داخل براکت را تا وقتی اجرا می‌کند (دقیقا نفهمیدم با چه زمانی :)) )

همون‌طورکه حدس می‌زنید در این زبان string به کلی وجود ندارد، آن هم نه مثل c که با char* هندل بشود بلکه به کلی وجود ندارد و یه helloworld ساده مشابه زیر خواهد بود:

>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.++++++++++.[-]
>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++
.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++.

البته چندین مدل دیگر هم امکان پیاده‌سازی helloworld وجود دارد و این نشان از قدرت و انعطاف پذیری زبان است. #شوخی

از مصاعب استفاده از زبان غیر از خود زبان، سرچ کردن چیزی مربوط به آن است که با توجه به تعدد روش های نوشتن اسم زبان شما را مجبور به چندین با سرچ می‌کند.

چند آموزش مفید برای زبان:

https://blog.klipse.tech//brainfuck/2016/12/17/brainfuck.html

http://cydathria.com/bf/brainfuck.html

به نظرم ایشون واقعا تلاش شایسته تقدیری کرده و چندین الگوریتم و برنامه معروف رو به این زبان نوشته:

http://www.hevanet.com/cristofd/brainfuck/

چند مفسر آنلاین هم هست که برنامه‌هاتون رو می‌تونید توش اجرا کنید:

https://fatiherikli.github.io/brainfuck-visualizer/

https://sange.fi/esoteric/brainfuck/impl/interp/i.html

https://copy.sh/brainfuck/

یکی از تمرین‌های خوب هم نوشتن یک کامپایلر برای brainf*ck هست (که من هم انجامش دادم :) ) با کمی سرچ آموزش‌ها و سورس کد‌های مرتبط رو می‌تونید پیدا کنید.


یک اصطلاح معروف هست که می‌گویند فلانی اقیانوسی به عمق یک سانت(یا یک وجب!) است یعنی دانش وسیعی در حوزه‌های محتلف دارد ولی دانشش عمق کمی دارد و هیچ‌کدام برای انجام کار جدی مفید نیستند، در بیش‌تر وقت‌ها فرد عطش یادگیری دارد(که بسیار خوب است) ولی در زمینه‌های مختلف یادگیری‌ می‌کند ولی در نهایت در هیچ کدام تخصّص ندارد (یعنی مثلاً hello world بلد هست!)؟

ادامه مطلب

آخرین ارسال ها

آخرین جستجو ها


New NFL Cheap Philadelphia Eagles Jerseys,Professional Jerseys Apply for You. 67 درجه golshanty pichakenk تفکر مدیریتی و مدل سازی مدیریت استراتژیک Timothy کسب بیت کوین رایگان اللهم عجل لولیک الفرج بحق زینب کبری سلام الله علیها من و روزهایم با کنکور وبلاگ خبری شهر سبزوار