آشنایی با Functional Programming

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

هر کجا بروید برنامه نویسی شئ‌گرا با شما خواهد بود – مگر آنکه این حالت تغییر کرده باشد.

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

الگوها

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

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

برنامه‌نویسی تابعی، شئ‌گرا و رویه‌ای همگی شکل‌های مختلفی از برنامه‌نویسی هستند. برخی از زبان‌های برنامه‌نویسی از یک الگوی مشخص پیروی می‌کند اما این موضوع باعث نمی‌شود که دیگر الگوها بی استفاده به نظر برسند.

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

درک الگوهای Declarative و Imperatively

دو راه کلی برای برنامه‌نویسی وجود دارد – Imperatively و Declarative. در حالت Imperatively برنامه‌نویس روی توضیح اینکه برنامه‌ چگونه کار می‌کند تمرکز دارد. به صورت کلی این شکل از برنامه‌نویسی یک لیست از دستورات است که به صورت نوبتی به یک کامپیوتر برای اجرا داده می‌شود. شما نمی‌توانید یکی از دستورات (قدم‌ها) را حذف کرده و یا برای یکی از دستورات بیشتر از بقیه ارزش قائل شوید.

یک مثال ساده از این حالت در دنیای واقعی:

- شروع

- وضعیت اولیه در رو چک کن.

- اگه در بسته بود، در رو باز کن.

- وضعیت جدید در رو به خاطر بسپار و حالا از در عبور کن.

- در رو ببند.

- پایان

در روال بیرون رفتن از یک در به صورت کلی این اتفاقات می‌افتد. اما تصور کنید که اگر شما قسمتی از این حالت را فراموش کنید و یا آن را انجام ندهید، چه اتفاقی خواهد افتاد؟ هیچوقت نمی‌توانید به درستی بیرون بروید و یا آنکه در را بدون بسته شدن رها می‌کنید. «یا اینکه بدون باز کردن در سعی می‌کنید از اون رد بشید!»

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

قواعد جبر در ریاضی می‌تواند مثال خوبی از برنامه‌نویسی Declarative باشد:

1 + 2 + 3 + 4 + 5 = 15
2 + 4 + 5 + 3 + 1 = 15
(3 x 5 x 8) + 12 - 5 + (2 x 5) = 137
(5 x 2) - 5 + 12 + (5 x 3 x 8) = 137

یک روش دیگر برای درک برنامه‌نویسی Declarative این است که در آن شما اگر ورودی‌های متفاوتی را وارد کنید در نهایت به یک خروجی قابل انتظار می‌رسید. برای مثال تصور کنید که ما قصد داریم تا با انجام اعمال یکسری ورودی روی یک مرغ وی را تبدیل به یک گاو بکنیم!

مشکل: قصد دارم با اعمال یکسری ورودی یک مرغ را به یک گاو تبدیل بکنم:

ورودی‌ها:

- ۴ تا پا بهش اضافه کن

- پاهاش رو درازتر بکن

- حجم مرغ رو بیشتر کن

- صداش رو به «مووو» تغییر بده

-و…

در نهایت شما قصد دارید تا خروجی «گاو» را ایجاد کنید.

بدرود State

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

در زمان تست کردن برنامه، خروجی شما تنها براساس مقادیری خواهد بود که در پروسه اجرا به برنامه‌ داده‌اید.

حال بیایید به یک مثال دیگر نگاه کنیم:

let ticketSales = [
   {name:'Twenty One Pilots', isActive: true, tickets:430}, 
   {name:'The Wiggles Reunion', isActive: true, tickets:257},
   {name:'Elton John', isActive: false, tickets:670}
]
/*using imperative*/
let activeConcerts = [];
for (let i = 0; i < ticketSales.length; i++){
    let t = ticketSales[i]; 
    if(t.isActive){ 
    activeConcerts.push(t)
  }
}

کدهای بالا از الگوی Imperative بهره می‌برند. زمانی که شما از این الگو استفاده بکنید نیاز دارید که دقیقا یک روال را به صورت قدم به قدم جلو ببرید تا بتوانید یک خروجی درست را بدست بیاورید. در این ساختار ما به یک state نیاز خواهیم داشت و از طرفی دیگر اگر مقدار i به صورتی از range خارج شده و با خطا مواجه شود، شانس اینکه خروجی اشتباهی به وجود بیاید بسیار زیاد است.

/*using declarative style of coding using the same data*/
let activeConcerts = [];
activeConcerts = (ticketSales.filter((t)=>{
   return t.isActive;
}))

مثال بالا از روش Declarative استفاده می‌کند. در این روش نیز از یک مجموعه داده ثابت استفاده می‌شود اما فرایند پردازشی در این حالت بسیار متفاوت است. وجود چندین متد برای Array در جاوااسکریپت به ما این قابلیت را می‌دهد تا به صورت مستقیم از برنامه‌نویسی تابعی استفاده کنیم. find، map، reduce، every و some جزو این توابع هستند.

در پایان

در حالیکه ما تنها تلاش کردیم تا بخش کوچکی از برنامه‌نویسی تابعی را شرح دهیم اما این موضوع تازه شروع شده و احتیاج به راهنماهای بسیار بیشتری دارد.

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

برای مطالعه بیشتر این قضیه می‌توانید به مطالب زیر مراجعه کنید:

تفاوت بین برنامه‌نویسی تابعی و شئ‌گرا
مزایا و معایب برنامه‌نویسی تابعی
اهمیت برنامه‌نویسی تابعی در پایتون - مصاحبه با Steven Lott
درس‌هایی که در طی دو سال برنامه‌نویسی تابعی JavaScript یاد گرفتم
مقدمه‌ای بر برنامه‌نویسی تابعی در پایتون