PDA

View Full Version : مقاله: برنامه نویسی تابعی در سی شارپ



Mehdi Asgari
یک شنبه 03 آذر 1387, 21:18 عصر
سلام
این اولین پست از سری مقالات "برنامه نویسی تابعی در C#" هست. تعداد مقالات مشخص نیست ، ولی تمامی مفاهیم تابعی پشتیبانی شده در C# مطرح خواهند شد.
نکات ایمنی:
1- لطفا اگر سوالی هست ، پس از حصول اطمینان از درک این مقاله (و مطالعۀ مقالات مرجع و لینک های داده شده) ، در صورت حل نشدن ، اون رو در همین تاپیک مطرح کنید. عمده ی مثال ها به زبان C# هستن و در برخی قسمت ها برای درک بیشتر ، از زبان های F# ، Haskell و Scheme هم استفاده می کنم. لطفا برای تشکر یا سوالات خیلی ساده پست جدید ایجاد نکنید (نه فقط در اینجا ، بلکه در هر تاپیک مقاله ای) (این رو هم در نظر بگیرید که سطح این مطالب "متوسط تا پیشرفته" هست)
2- من ادعایی در زمینۀ Functional Programming ندارم ، فقط چون خودم الان در حال یادگیری این موضوع هستم ترجیح دادم آموخته هام رو در اینجا قرار بدم. به قول بنیامین دیزرائلی "بهترین روش برای آشنایی با یک موضوع ، نوشتن کتابی دربارۀ اون موضوعه!"
3- تمامی این پست ها ترجمه هستن ، منتها ترجمۀ آزاد از کلی منبع و به صورت در هم آمیخته (یعنی هیچ جمله ای رو مستقیما از جایی برنداشتم ، بلکه اون چیزی رو که خودم از این مقالات و کتاب ها فهمیدم ،نوشتم. تمامی منابع و لینک ها رو خودم کاملا مطالعه کرده و تمامی مثال ها رو تست کردم)
4- این اولین سری از مقالاتمه. احتمالا سری بعدی ، Concurrency (http://en.wikipedia.org/wiki/Concurrency_(computer_science))+ TPL (http://en.wikipedia.org/wiki/Parallel_FX_Library)باشه. (یکی از دلایل توجه بیشتر برنامه نویسان و شرکت های بزرگ برنامه نویسی نسبت به برنامه نویسی تابعی ، موازی شدن راحت تر اون ها به دلیل نداشتن side effect (http://en.wikipedia.org/wiki/Side_effect_(computer_science)) هست)
قسمت 0 : مقدمه (تئوری ها ، مفاهیم و تاریخچه):
علم کامپیوتر مدیون ریاضی دانان زمان جنگ جهانی دومه. خیلی از مفاهیم بنیادی این رشته در این سال ها (دهۀ 30 و 40 میلادی) مطرح شدن ؛ زمانی که هنوز کامپیوتر (به شکل امروزی و گسترده) در دسترس کسی نبود (به استثنای مراکز نظامی). یکی از مراکزی که نخبه های اون زمان رو یک جا جمع کرده بود ، دانشگاه پرینستون (www.princeton.edu/)امریکا بود. آلن تورینگ (http://en.wikipedia.org/wiki/Alan_Turing) ، جان فون نیومن (http://en.wikipedia.org/wiki/John_von_Neumann) ، آلونزو چرچ (http://en.wikipedia.org/wiki/Alonzo_Church) و ...
در سال 1936 ، آلن تورینگ و آلونزو چرچ همزمان به حل مسئلۀ لایبنیتز (http://en.wikipedia.org/wiki/Gottfried_Leibniz)پرداختن (پیدا کردن روشی برای حل تمامی مسائل که در زبان جهانی (universal language) بیان شدن) روش تورینگ رو حتما شنیدید (ماشین تورینگ (http://en.wikipedia.org/wiki/Turing_machine))؛ ماشین های فون نیومن (همین کامپیوترهایی که ازشون استفاده می کنیم) نوعی ماشین تورینگ هستن ؛ همینطور زبان های دستوری مثل اسمبلی ، سی ، پاسکال ، .... بر این اساس کار می کنن (یعنی رشته ای از دستورات)
و اما روش آقای چرچ که اساس برنامه نویسی تابعی رو تشکیل میده ، حساب لامبدا (http://en.wikipedia.org/wiki/Lambda_calculus) هست. حساب لامبدا رو توضیح نمی دم ، به منابع مراجعه کنید. این روش مبنی بر توابع هست (بعدا می بینیم که در زبان های تابعی محض ما متغیر نداریم و همه چیز تابعه و immutable) آقای تورینگ ثابت کرد که هر دو روش از نظر قدرت برابرن.
اصول برنامه نویسی تابعی همونطور که از اسمش پیداست ، تابعه. ما تابع تعریف می کنیم ، آرگومان های توابع از نوع تابع هستن ، تابع بر می گردونیم ، از بازگشتی استفاده می کنیم ، در واقع محاسبۀ هر چیزی بر اساس تابع هست.
در سال 1958 آقای مک کارتی (http://en.wikipedia.org/wiki/John_McCarthy_(computer_scientist)) LISP (http://en.wikipedia.org/wiki/Lisp_(programming_language)) رو به وجود آورد که اولین زبانی بود که بر اساس حساب لامبدا کار می کرد. (البته کاملا تابعی نبود).از پیاده سازی های معروف میشه به GNU CLISP (http://clisp.cons.org/) اشاره کرد.
از اون موقع تا الان زبان های تابعی زیادی به وجود اومدن :
• Scheme (http://en.wikipedia.org/wiki/Scheme_(programming_language)): توسط Guy Steele (http://research.sun.com/minds/2005-0302/) به وجود اومد. از dialect (http://en.wikipedia.org/wiki/Programming_language_dialect)های LISP هست. (اگه کد LISP یا Scheme رو دیده باشید ، متوجه میشید که خیلی از پرانتز استفاده میشه در این زبان ها) عیب بزرگ Scheme نبود استانداردی واحده ، برای همین پیاده سازی های مختلفی از اون وجود داره (معروف ها: PLT Scheme (http://www.plt-scheme.org/) ، Scheme48 (http://s48.org/)، Ikarus (http://www.cs.indiana.edu/~aghuloum/ikarus/)، IronScheme (www.codeplex.com/IronScheme) ....) Scheme برای تدریس "آشنایی با برنامه نویسی" در یک سری دانشگاه ها و مراکز آموزشی استفاده میشه. (http://www.schemers.com/schools.html) (معروف ترینش کلاس 6.001 (http://ocw.mit.edu/OcwWeb/Electrical-Engineering-and-Computer-Science/6-001Spring-2005/CourseHome/) دانشگاه MIT (http://mit.edu/)برای رشتۀ "Computer Science" بود که اخیرا به جاش از پایتون استفاده می کنن.) توجه: سال 2007 بالاخره یه استاندارد R6RS (www.r6rs.org)به وجود اومد ، ولی هنوز همۀ نسخه ها اون رو پیاده سازی نکردن
• Haskell (http://en.wikipedia.org/wiki/Haskell_(programming_language)): گل سر سبد زبان های تابعی ؛ یکی از معدود زبان هایی که "تابعی محض" هستن (pure functional (http://en.wikipedia.org/wiki/Purely_functional))
• ML (http://en.wikipedia.org/wiki/ML_programming_language): از موفق ترین زبان های تابعی هست. در واقع مثل C زبان های تابعی میمونه. دو dialect بزرگ داره: SML (http://en.wikipedia.org/wiki/Standard_ML)و OCAML (http://en.wikipedia.org/wiki/OCaml)
• Erlang (http://en.wikipedia.org/wiki/Erlang_(programming_language)): توسط شرکت اریکسون (http://en.wikipedia.org/wiki/Ericsson)به وجود اومد و شهرتش رو مدیون پشتیبانی خوبش از concurrent programming (http://en.wikipedia.org/wiki/Concurrent_computing) و real-time computing (http://en.wikipedia.org/wiki/Real-time) هست.
• F# (http://en.wikipedia.org/wiki/F_Sharp_(programming_language)): توسط شرکت مایکروسافت در سال 2005 به وجود اومد (بر اساس OCaml ؛ در واقع سازگاری زیادی با OCaml داره) این زبان علاوه بر برنامه نویسی تابعی ، از OOP (http://en.wikipedia.org/wiki/Object-oriented_programming)هم پشتیبانی می کنه. مزیت بزرگ این زبان (به غیر از پشتیبانی مایکروسافت) بهره گیری از .Net Framework هست که بر خلاف بسیاری از زبان های تابعی ، لااقل مشکل library نداره.

توجه: این زبان ها ، بر روی ماشین های فون نیومن اجرا میشن (همون کامپیوتر های خودمون)، ولی در قدیم ماشین های مخصوصی هم برای بعضی از زبان ها وجود داشته (مثل LISP Machines (http://en.wikipedia.org/wiki/Lisp_machine))
شاید قبلا شنیده باشید که این زبان ها به درد برنامه نویسی واقعی نمی خورن و بیشتر توسط دانشگاهیان و جامعۀ آکادمیک استفاده میشه. بخش اول این حرف غلط و بخش دومش درسته.
هیچ محدودیتی در ایجاد برنامه های واقعی (وب ، پایگاه داده ، گرافیک ، .... ) توسط زبان های تابعی وجود نداره ، این هم لیستی از برنامه های نوشته شده در زبان های تابعی و کاربرد اون ها:
http://homepages.inf.ed.ac.uk/wadler/realworld/
http://bc.tech.coop/blog/041027.html
http://caml.inria.fr/about/successes.en.html
http://wiki.cocan.org/ocaml_success_stories

در بخش jobs خیلی از شرکت ها هم برنامه نویس "OCaml" ، LISP و ... خواهید دید.
پس چرا در برنامه نویسی mainstream کمتر از این زبان ها استفاده میشه ؟
بعضی ها میگن یادگیری و کار با این زبان ها سخته. هر چیز ناآشنا و جدیدی برای اولین بار سخت به نظر می رسه. (فکر کنید اگه از اول با زبان های تابعی کار کرده بودیم ، یادگیری زبانی مثل C برامون خیلی سخت می شد)
نبود استاندارد جامع و کتابخانه های توابع هم یه مشکله. به اینجا (http://community.schemewiki.org/?scheme-faq-standards#implementations) یه سری بزنید تا ببینید چقدر پیاده سازی مختلف از Scheme داریم (که به غیر از هستۀ زبان ، هیچ چیزیشون با هم سازگار نیست. گاها بعضی ساختار های زبانی مثل unless هم بین نسخه ها فرق می کنه)
تاکید بیش از حد بر روی نداشتن side effect در بعضی زبان ها هم باعث کاهش محبوبیتشونه: به قول آقای Hejlsberg (http://channel9.msdn.com/posts/Charles/Anders-Hejlsberg-and-Guy-Steele-Concurrency-and-Language-Design/) ، "به هرحال ما باید یک چیزی رو در صفحه نمایش بدیم یا نه ؟" و این همون side-effect هست (یعنی تغییر state) (در اینجا (http://channel9.msdn.com/posts/Charles/Simon-Peyton-Jones-Towards-a-Programming-Language-Nirvana/)آقای Peyton-Jones (http://en.wikipedia.org/wiki/Simon_Peyton_Jones) در مورد راه حل هایی برای افزایش "مفید بودن" و "کارایی" Haskell صحبت می کنه .
بعضی از زبان های تابعی هم سرعت پایینی در اجرا دارن (البته الان زبان هایی مثل OCaml فوق العاده سریع هستن: http://shootout.alioth.debian.org)
این زبان ها پایۀ ریاضی و تئوری قوی ای دارن و برای حل مسائل علمی خیلی مناسبن و همین باعث جلب توجه جامعۀ اکادمیک شده.
خب ، الان همه چیز فرق کرده:
در چند سال اخیر توجه بیشتری به این زبان ها مبذول شده ؛ مثال بارزش ارائۀ زبان F# از تیم تحقیقاتی مایکروسافت هست (در ابتدا آقای Don Syme (http://research.microsoft.com/~dsyme/) به تنهایی روی این زبان کار می کردن) که قراره در نسخۀ بعدی VS جزو زبان های first class مایکروسافت باشه.
یکی از دلایل ، متوقف شدن قانون Moore (http://en.wikipedia.org/wiki/Moore%27s_law) هست (افزایش سرعت پردازنده ها هر 18 ماه یک بار) الان به جایی رسیدیم که نمی تونیم مثل دهۀ قبل ، برنامه هامونو بنویسیم و از آخرین فن آوری ها استفاده کنیم و خیالمون راحت باشه که پردازنده ها روز به روز دارن سریع تر میشن و برنامه های ما بدون مشکل اجرا خواهند شد. الان عصر Many Core (http://en.wikipedia.org/wiki/Many-core) هست (سرعت تقریبا ثابت مونده ، و تعداد هسته ها افزایش پیدا می کنه.) و این یعنی اگه پرفورمنس بالاتری میخوایم باید برنامه هامون رو طوری بنویسیم که بتونن بر روی thread های مختلف (به نوبۀ خود ، روی چند هسته) اجرا بشن.
خب این چه ربطی به زبان های تابعی داره ؟ زبان های تابعی به دلیل نداشتن side effect (اثر جانبی) قابلیت "موازی شدن" بالایی دارن. یعنی کامپایلر می تونه خیلی راحت دو بخش از برنامه رو موازی کنه (و خیالش راحته که دچار مشکلاتی مثل همزمانی (http://en.wikipedia.org/wiki/Synchronization_(computer_science))و race condition (http://en.wikipedia.org/wiki/Race_condition) و ... نخواهد شد ، چون اصولا بخش اول هیچ state(حالتی) رو تغییر نمیده ، تا این تغییر حالت باعث ایجاد مشکل در بخش دوم بشه. حالا قرار نیست حتما برای پردازش موازی از این زبان ها استفاده کنیم ، ولی می تونیم ازشون ایده بگیریم (کاری که آقای Hejlsberg در سی شارپ کرد و موضوع این سری مقالات هست)
از دیگر دلایل افزایش محبوبیت این زبان ها ، تبلیغ بزرگان (Paul Graham (http://en.wikipedia.org/wiki/Paul_Graham) ، ESR (http://www.catb.org/~esr/faqs/hacker-howto.html#skills1)، ... ) و چاپ کتاب های مختلف در زمینۀ برنامه نویسی "واقعی" با این زبان ها در سال های اخیره (مثال مشهور: Practical Common LISP (http://gigamonkeys.com/book/))

برای آشنایی با سینتکس این زبان ها ، یه برنامۀ کوچیک برای محاسبۀ عدد فیبوناچی با سه زبان سی شارپ ، F# و Scheme می نویسیم:


// C# version
using System;
class Program
{
static int Fibo(int n)
{
if (n <= 1)
return n;
else
return Fibo(n - 1) + Fibo(n - 2);
}
static void Main()
{
int i = Convert.ToInt32( Console.ReadLine());
Console.WriteLine("Fibo({0}) = {1}", i, Fibo(i));
}
}
-------------------------------------------------------------------------------
// F#
#light
open System
let rec fibo n =
match n with
0 -> 0
| 1 -> 1
| n -> fibo(n - 1) + fibo(n - 2)
let i = Int32.Parse(Console.ReadLine())
Console.WriteLine(fibo i)
-------------------------------------------------------------------------------
;Scheme
(define fibo
(lambda (x)
(if (< x 2)
x
(+ (fibo (- x 1)) (fibo (- x 2))))))
(define getInp
(lambda()
(let ((a (read)))
(cond ((number? a) (display (fibo a)))))))
(getInp)


مفاهیم و اصطلاحات:
Side effect: هر چیزی که حالت (state) ماشین رو تغییر بده گفته میشه. (چاپ چیزی در خروجی ، تغییر مقدار یک متغیر ، ... )
Pure functional: زبانی که فقط برنامه نویسی تابعی رو پشتیبانی می کنه. (بیشتر زبان های تابعی multi-paradigm (http://en.wikipedia.org/wiki/Multi-paradigm_programming_language) هستن ، یعنی ساختار هایی از دیگر زبان ها رو هم تا حدودی پشتیبانی می کنن)
First class function (http://en.wikipedia.org/wiki/First-class_function): اگه زبانی بتونه در زمان اجرا تابع ایجاد کنه ، توابع رو در ساختار های داده های ذخیره کنه ، توابع رو به عنوان پارامتر به دیگر توابع ارسال کنه و از تابع به عنوان نوع برگشتی توابع پشتیبانی کنه ، می گیم که توابع در اون زبان first class هستن
Higher-order function (http://en.wikipedia.org/wiki/Higher-order_function): تابعی که یا "یک یا چند تابع رو به عنوان آرگومان می گیره" یا "نوع برگشتی اش تابع هست"
Recursion (http://en.wikipedia.org/wiki/Recursion_(computer_science)): از ساختار هایی که استفادۀ خیلی زیادی در زبان های تابعی داره ، "تابع بازگشتی" هست.
Lazy Evaluation (http://en.wikipedia.org/wiki/Lazy_evaluation): ارزیابی تنبل ؛ فکر کنم تو درس "طراحی و پیاده سازی زبان های برنامه سازی" در مقطع کارشناسی مهندسی کامپیوتر (گرایش نرم افزار) این مفهوم رو خوندیم. یه آدم تنبل ، معمولا دقیقه نودی عمل می کنه ؛ تا مجبور نشه کاری رو نمی کنه. ارزیابی تنبل هم یعنی تا وقتی که به یک تابع (مقدار) نیاز نداشته باشیم ، فراخوانی نمیشه (ارزیابی نمیشه) مثال زیر رو ببینید:


static int F(bool cond, int arg)
{
if (cond)
return arg;

return 0;
}

static void Main(string[] args)
{
int x = SomeFunction ();
F(false, x);

}

تابعی تعریف کردیم که یک متغیر شرط (bool) می گیره و یک عدد ؛ اگه شرط درست بود ، اون عدد رو بر می گردونه ، وگرنه مقدار صفر رو برمی گردونه.
فرض کنید SomeFunction یک تابع سنگین باشه که نیاز به زمان طولانی ای (مثلا 10 ثانیه) برای اجرا داره و cond هم false هست. در یک زبان معمولی ، هنگام فراخوانی کد بالا ، ابتدا SomeFunction فراخوانی شده ، مقدار اون در x ریخته میشه و x به عنوان arg به F داده میشه ، ولی ازش استفاده ای نمیشه! چون شرط false هست. در زبان هایی که از lazy evaluation پشتیبانی می کنن ، وقتی SomeFunction فراخوانی خواهد شد که شرط درست باشه و ما نیاز به مقدار x داشته باشیم. (البته این روش مزایا و معایب خودش رو داره؛ بعضی زبان ها اجازه میدن که خودتون یه statement رو lazy کنید در صورت نیاز) یکی از موارد استفادۀ lazy evaluation ایجاد لیست های نامتناهی هست (وقتی عنصر n+1 ایجاد خواهد شد که نیاز باشه. با yield در سی شارپ همچین چیزی رو میشه شبیه سازی کرد)

این برای جلسۀ اول
(به یکی از مدیران گفته بودم اولین مقاله رو دو هفتۀ قبل میدم ، ولی الان تونستم بنویسم. {شکلک خجالت + سرشلوغی!})

اینم بخونید:
http://www.md.chalmers.se/~rjmh/Papers/whyfp.html

Mehdi Asgari
پنج شنبه 07 آذر 1387, 19:21 عصر
قسمت 1:
کلمۀ کلیدی var:
نوع متغیر های تعریف شده از طریق var ، از طریق مکانیسمی به نام type inference (http://en.wikipedia.org/wiki/Type_inference) تعیین میشه. (در واقع با استفاده از var ، متغیر ها implicitly typed (http://msdn.microsoft.com/en-us/library/bb384061.aspx) هستن و چیزی از strong typed بودن زبان کم نمیشه)
در زبان های دیگر هم قبلا همچین چیزی داشتیم ، مثل let در Ocaml (البته در زبان های دینامیک مثل JavaScript (var) هم همچین چیزی داشتیم ، منتها اون فرق داره و واردش نمیشم)
کلمۀ کلیدی var به تنهایی چیزی از دنیای برنامه نویسی تابعی به سی شارپ اضافه نکرده ولی در جاهایی مثل LINQ (http://en.wikipedia.org/wiki/Language_Integrated_Query)، کد رو کوتاهتر و نزدیکتر به سینتکس زبان های تابعی می کنه.
برای این که مطمئن بشید که همچنان زبان استاتیک و strong typed بوده و در زمان کامپایل نوع همۀ متغیر ها معلومه ، سعی کنید کد زیر رو کامپایل کنید:


var x = 567;
x = 4.5;

دلیلش هم اینه که در خط اول ، کامپایلر نوع x رو از عبارت سمت راست ، می فهمه : int . پس دیگه نمی تونیم یک مقدار double رو در یک متغیر از نوع int قرار بدیم. همینطور کد زیر رو در fsi (FSharp Interactive) بنویسید:


let f x = x * x ;;

پس از فشردن دکمۀ Enter ، در کنسول می نویسه:
val f : int -> int
یعنی فهمیده که f تابعی است که یک int رو گرفته و یک int برمی گردونه.
برای درک تفاوت این مثال ها با زبان های دینامیک ، کد زیر رو در JScript بنویسید:


var x = "Hi”;
x = 10;
WScript.Echo(x(;

کد اجرا شده و عدد 10 در یک دیالوگ نشون داده میشه .

توابع بی نام و توابع لامبدا:
در نسخۀ 2 ، ویژگی ای به نام anonymous methods (http://msdn.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspx) یا متد های بی نام به زبان اضافه شد ، که می تونستیم به جای ایجاد یک event handler (http://en.wikipedia.org/wiki/Event_handler) (یک متد جداگانه) برای handle کردن یک رویداد ، درون همون متد ، کد رو بنویسیم. مثال:


private void Form1_Load(object sender, EventArgs e)
{
button1.Click += delegate
{
// ....
MessageBox.Show("Hello anonymous method");
// ...
};
}
در این مثال قطعه کدی که بین آکولاد delegate و semicolon هست ، متدی است بی نام.
در سی شارپ نسخه ی 3 با استفاده از توابع لامبدا (http://msdn.microsoft.com/en-us/library/bb397687.aspx) ، کار از اینم راحت تر شد:


private void Form1_Load(object sender, EventArgs e)
{
button1.Click += (obj,eArgs) => MessageBox.Show("Hello");
}

البته توابع لامبدا در سی شارپ محدودیت هایی دارن. (break ، continue ، goto ، بازگشتی ، ...)
(توابع لامبدا بیشتر برای پشتیبانی از LINQ به زبان اضافه شدن)
یه مثال دیگه از تابع لامبدا در سی شارپ: (چاپ تعداد اعدادی که مضرب سه هستن در یک ارایه)


int[] arr = { 10,23,11,6,90,45,8,34};
Console.WriteLine(arr.Count(i => (i % 3) == 0));

مثال از لامبدا در Python: (یک تابع یک خطی برای محاسبۀ توان یک عدد)


fun = lambda x : x * x
fun(9)

مشابه دو کد سی شارپ در F# :


#light
#r "System.Windows.Forms.dll"
open System
open System.Windows.Forms

let form = new Form()
let button = new Button(Text="Click Me!”)
form.Controls.Add(button(
button.Click.Add(fun _ -> MessageBox.Show("Hello") |> ignore(
Application.Run(form)

یک مثال از انتساب توابع به یک متغیر در سی شارپ (تابعی که یک متغیر رو گرفته ، مربعش رو برمیگردونه)


Func<int, int> f = (i) => { return i * i; };
Console.WriteLine(f(9));

محدودیت: نمی تونیم از بازگشتی استفاده کنیم (کد زیر در سی شارپ غلط هست)


Func<int, int> factorial = delegate(int i)
{
if (i <= 1)
return 1;
return i * factorial(i - 1);
};

همین کد اما در زبان های تابعی درسته. مثال از F#:


let rec factorial i =
if i <= 1 then
1
else
i * factorial (i – 1);;
factorial(5);;

Delegate ها ، توابع بی نام و مخصوصا Func (http://msdn.microsoft.com/en-us/library/bb549151.aspx)، یادآور LISP هست که برای اولین بار این موضوع رو مطرح کرد که کد و داده با هم برابرن (یعنی کد رو میشه در ساختار های داده ای ذخیره کرده و داده رو مثل کد اجرا کنیم) اینجا هم کد رو داخل یک متغیر می ریزیم. در بخش Expression tree بحث های جالبتری داریم.
Closure (http://en.wikipedia.org/wiki/Closure_(computer_science))ها:
نمی دونم ترجمۀ Closure چیه. Closure تابع لامبدایی (یا بی نام) است که به متغیر های تابعی که در اون تعریف شده ، دسترسی داره. مثال:


static void Main(string[] args)
{
int x = Int32.Parse(args[0]);
Func<int, int> f = (i) => { return i * x; };
Console.WriteLine(f(9));
}

در اینجا f و x با هم یک closure تشکیل میدن.
مثالی از پایتون و Scheme:


#Python
def f(x):
def g(y):
return x * y
return g
print f(9)(10)
;Scheme
(define (f x)
(lambda (y) (* x y)))
((f 9) 10)

List Comprehension (http://en.wikipedia.org/wiki/List_comprehension):
ایجاد یک لیست بر اساس یک لیست دیگه:
اول تعریف ریاضی اش رو ببینید:
http://upload.wikimedia.org/math/e/f/e/efe0811ead0b5ff85b1036c388b1439e.png
می خونیم: به ازای هر x در لیست اول (اعداد طبیعی) ، 2x رو چاپ کن به شرطی که مربع x بیشتر از 3 باشه.
همین مثال در سی شارپ (توسط LINQ و برای اعداد 1 تا 100 و با شرط مربع کمتر از 50):


var q = from x in Enumerable.Range(1, 100)
where x * x < 50
select x * 2;
foreach (int i in q)
Console.WriteLine(i);

همین مثال در F# و پایتون :


let q = seq { for x in 1..100 do
if x*x < 50 then yield x*2};;

#python
q = [x*2 for x in range(100) if x**2 < 50]


Higher order function:
قبلا تعریفشو گفتم. مثال:


static int hof(Func<int, int> func, int arg)
{
return func(arg);
}

static void Main(string[] args)
{
Console.WriteLine(hof((i) => { return i * 2; },7));
}

در اینجا hof یک تابع مرتبه بالاتر هست نسبت به func (چون اون رو به عنوان آرگومان می گیره)
در مثال زیر هم تابع رو به آرگومان می گیریم و هم برمی گردونیم:


static Func<int> hof(Func<int,Func<int>> func, int arg)
{
return func(arg);
}

static void Main(string[] args)
{
Console.WriteLine(hof((i) => { return delegate(){return i*i;}; },7)());
}

Currying:
در Wikipedia اومده (http://en.wikipedia.org/wiki/Currying): "Currying تکنیک تبدیل یک تابع چند آرگومانی به چند تابع تک آرگومانی است"
تابعی که یک آرگومان گرفته با 10 جمع کرده و جواب رو بر می گردونه (توسط تابع دو ارگومانی add)


static int add(int x, int y)
{
return x + y;
}

static void Main(string[] args)
{
Func<int, int> add10 = delegate(int x)
{
return add(x, 10);
};

Console.WriteLine(add10(7));
}

مثال از F#:


let add x y = x + y;;
let add10 x = add x 10;;
add10(7);;

تا مقالۀ بعد.

اَرژنگ
پنج شنبه 14 آبان 1388, 05:48 صبح
ایجاد یک لیست بر اساس یک لیست دیگه:
اول تعریف ریاضی اش رو ببینید:

چند نقته کوچک :
این تعریف ریاضی لیست نیست، تعریف ریاضی ست Set است، ستها در ریاضیات با لیستهایه علم کامپیوتر فرق دارند.
تعریف ست در ریاضیات دو شکل مختلف دارد:
با توضیح ساختن اجزاء به صراحت Constructive
با امتحان کردن اجزاء یک یک Non-Construcive
در منبعی که استفاده شده این فرق را بیان نکرده، این گونه تفکیکات در ریاضیات ،منطق ، فلسفه و ست تئوری بسیار مهم هستند و در ِعلم‌کامپیوتر فقط با گروه اول کار میشه.
نقته دوم:
مقایسه یک زبان فانکشنال با یک زبان شئی‌گرا درست نیست، نشان دادن فرق بین پیاده کردن یک فانکشن در سی‌شارپ با یک متد استاتیک و اف‌شارپ که برایه کار کردن بر فانکشانها بنا شده درست نیست.
سی‌شارپ برایه پیاده سازی مفاگیم شئیگراست، "برنامه نویسی تابعی در سی شارپ" عنوانی گمراه کننده است، درستش "استفاده از ساختارهایه زبانهایه تابعی در سی‌شارپ" (Using Functional Progamming Constructs in C#) است.
روشی که برایه پیاده کردن سری فیبانوچی در سی‌شارپ همه‌جا به چشم میخورد ، شئیگرائی نیست. روش درست هر عنصر سری را به شکل شئی میسازد.
این اشکال گیری از شما نیست، در هر منبع زبان اصلی نویسنده‌ها به ندرت قابلیت تفکیک مفاهیم را دارند ، دلیلش هم این است که هم اکنون معدود افرادی در علم کامپیوتر وجود دارند که با تاریخچه ریاضی و مفاهیم فلسفی و منطقی که باعث بوجود آمدنش شد آشنایی داشته باشند.
در مورد :
"علم کامپیوتر مدیون ریاضی دانان زمان جنگ جهانی دومه" ، درست نیست (هر وقت جایی شنیدید که به خاطر جنگ پیشرفتی حاصل شده در حقیقت یک عذر برایه جنگ است نه فایده واقعی جنگ) این برایه تبلیغات برندگان جنگ جهانی دوم استفاده میشه. قبل از جنگ جهنای دوم دیوید هیلبرت با ۱۰ سوالش به دنیایه ریاضی که به "برنامه هیلبرت" معروف شد بسیاری از جوانب را که الان به کار تورینگ و چرچ سرانجام شد را شروع کرد.
زحمتهایه فلسفه دان آلمانی (قبل از جنگ جهانه دوم) Frege http://plato.stanford.edu/entries/frege-logic/
و Gödel
http://en.wikipedia.org/wiki/Kurt_G%C3%B6del
و Pino و خیلی دیگر از فلسفه دانان و منطق دانهایه دیگر قبل از جنگ جهانی مداوم نادیده گرفته میشه.
در مورد تورینگ، بعد از زحمات بسیارش که باعث شد انگلیس جنگ را ببره ، بعد از جنگ به دلیل نحوه زندگیش که بر مذاق دولت انگیلس خوش نمیامد اول به حالت شیمیایی "مداوا" شد و بعد هم سازمان جاسوسی انگلیس کشتش.