PDA

View Full Version : اشنایی با زبان برنامه نویسی F# قسمت اول



r00tkit
یک شنبه 06 تیر 1389, 22:52 عصر
اشنایی با زبان برنامه نویسی F#(اسفند 87)


مولف: Mehdi Asgari (http://www.barnamenevis.org/forum/member.php?u=12705)

سطح: متوسط-پیشرفته

چکیده: F# یکی از جدیدترین زبان هایی است که توسط شرکت مایکروسافت ارائه شده است. چرا یک زبان دیگر ؟ آیا زبان های برنامه نویسی موجود کافی نیستند ؟ در این مقاله علاوه بر معرفی اجمالی زبان F# ، نگاهی هم به کاربردهای ان و تفاوت ها و شباهت هایش با زبان های موجود می اندازم.

از روزی که جان مک کارتی در سال 1958 زبان LISP را ایجاد کرد ، تا همین چند سال پیش شاهد پیشرفت های خیلی بزرگ و بنیادی در زبان های برنامه نویسی نبودیم. یعنی امروزه هم ما برای برنامه نویسی کد را در فایلی می نویسیم و تحویل کامپایلر می دهیم (و معمولا واحد جداکننده ، خط است) و هنوز از مفاهیمی که زبان LISP و زبان های دهه ی 60 میلادی معرفی کردند استفاده می کنیم (ارایه ، اشاره گر ، متغیر ، حلقه و ...) و بیشترین تغییرات را در ابزار (IDE ، دیباگر ، پروفایلر و ...) شاهد بودیم. (حتی مفاهیمی مثل GC هم از نسخه های اولیه ی لیسپ موجود بودند) شیوه ی برنامه نویسی ای که غالب برنامه نویسان به ان عادت کرده و با آن کد می نویسند (و بیشتر برنامه نویسان قادر به تصور برنامه نویسی به شکلی دیگر نیستند) ، روش دستوری (imperative) است (و نیز شی گرا)

زبان های برنامه نویسی ای که می شناسیم (سی ، پاسکال ، جاوا ، ...) بر مبنای مدل تورینگ هستند[1] (http://www.barnamenevis.org/forum/#_edn1). منتها مدل دیگری هم برای زبان های برنامه نویسی وجود دارد که شاید کمتر به گوشمان خورده باشد: حساب لامبدا. آقای Alonzo Church (پدر لامبدا!) و Allen Turing همزمان به این دو مدل دست یافتند و بعدا هم ثابت کردند که این دو زبان از نظر قدرت محاسباتی با هم برابرند. زبان های مبتنی بر مدل تورینگ ، معمولا دستوری هستند. نقطه ی مقابل زبان های دستوری ، زبان های بیانی (declarative) است که در ان ها به جای تاکید بر چگونگی انجام یک عمل (how) روی این که چه کاری را می خواهیم انجام دهیم (what) تاکید می کنیم. (مثل SQL که فقط با query ها می گوییم که چه می خواهیم ، ولی چگونگی انجامش را واگذار می کنیم به کامپایلر/مفسر)

زبان های تابعی هم به نوعی declarative محسوب می شوند (اکثر اوقات ما روی بخش what تاکید داریم تا how. در ادامه مثال خواهم آورد)

زبان های محبوب و رایج امروزی (سی پلاس پلاس ، جاوا ، دلفی ، سی شارپ ، روبی و ...) زبان های شی گرا هستند (مثال آخر بر خلاف بقیه یک زبان داینامیک است) (البته درست است که در سال های اخیر ویژگی های دیگری هم به این زبان ها اضافه شده که برنامه نویسی برای مدل های دیگر همچون تابعی را پشتیبانی می کند ، ولی باز هم هسته ی این زبان ها ، دستوری و شی گراست). زبان های تابعی به اندازه ی زبان های دستوری قدمت دارند (از LISP در سال 1959و Scheme در دهه ی 70 و Haskell و ML در دهه ی 80) منتها از عللی که باعث شده این زبان ها بیشتر در دنیای آکادمیک کاربرد و محبوبیت داشته باشن ، می شود موارد زیر را برشمرد:

· نداشتن کتابخانه های قدرتمند و وسیع

· نداشتن حمایت مالی شرکت های نرم افزاری

· عدم توانایی برقراری ارتباط با زبان های مهمی مثل سی برای ارتباط با سیستم عامل میزبان

· سرعت اجرای پایین

· شیب زیاد منحنی یادگیری

· و ....

البته تمام موارد فوق امروزه غلط هستند و مخصوصا در مورد سرعت اجرا زبان هایی مثل OCaml در موارد زیادی از سی هم سریع ترند (به دلیل نامرتبط بودن با این بحث ، محولش می کنم به یک مقاله ی دیگر ؛ فقط این نکته را اضافه کنم که علت سرعت پایین تر این زبان ها در گذشته محدودیت حافظه و قدرت پردازش کامپیوتر های ان زمان و نیز استفاده ی این زبان ها از GC و پویا بودن و یا انجام type checking های پیچیده (در مورد استاتیک ها) است که با توجه به سخت افزار های ضعیف ان روز ها سرعت اجرای پایین و حافظه ی مصرفی بالا داشتند.)

زبانی مثل Haskell کاملا شی گراست (pure functional) و برنامه نویسی به مدل های دیگر را پشتیبانی نمی کند. از دلایل موفقیت زبان OCaml این است که این زبان هم شی گراست و هم تابعی و به نظر من زبان هایی موفق ترند که چندین پارادایم را پشتیبانی کرده و دست برنامه نویس را باز می گذارند (حرکت اخیر مایکروسافت برای افزودن ویژگی های تابعی (LINQ, anonymous methods, expression trees,…) و پویا به زبان سی شارپ موید این نظر است)

F# محصول تیم تحقیقاتی کمبریج مایکروسافت به سرپرستی Don Syme ، پورتی از زبان OCaml برای.NET framework است. این زبان شی گرا ، تابعی و استاتیک است. خود OCaml از Caml و ان هم از ML مشتق شده اند. خانواده ی ML شامل دو زبر شاخه ی SML و Caml است که موفق ترینشان تا به امروز OCaml بوده. زبان های خانواده ی ML و همچنین زبان Haskell به دلیل استفاده از Type inference[2] (http://www.barnamenevis.org/forum/#_edn2) ، کد موجز و کوتاه تری در مقایسه با دیگر زبان های استاتیک دارند. (گرچه می شود برای خوانایی بیشتر یا کمک به ابزار مستندسازی یا ... ، نوع داده ها را هم در کد آورد. در نسخه ی 3 زبان سی شارپ هم ویژگی استنباط نوع از طریق کلمه ی کلیدی var اضافه شد).

F# در اصل یک زبان استاتیک است ، منتها با استفاده از محیط تعاملی این زبان (F# Interactive) می شود مثل زبان های پایتون و روبی ، به شکل داینامیک کد نوشت. در ضمن این زبان بر اساس سینتکس و مفاهیم زبان OCaml پیاده سازی شده (و کتابخانه های OCaml را جز تعداد اندکی ساپورت نمی کند) ، منتها مدل شی (object model) اش همانند سی شارپ است (به خاطر این که زبانی تحت دات نت است) و همچنین ویژگی indentation یا تورفتگی کدش ، یاداور پایتون است. در ضمن از Haskell و Erlang هم ویژگی هایی به ارث برده.

آخرین نسخه ی این زبان نسخه ی CTP 1.9.6.2 است که از وبسایت رسمیF# قابل دانلود است. در نسخه ی بعدی Visual Studio (نسخه ی 2010) این زبان در کنار Visual C++‎‎‎, C#‎‎‎ , VB جزو زبان های رسمی مایکروسافت خواهد بود. (مایکروسافت زبان های دیگری را هم به طور مستقیم و غیر مستقیم پشتیبانی می کند ؛ مثل SmallBasic ، Haskell ، OCaml و ... منتها زبان های رسمی مایکروسافت نیستند)

F# مزایای زیادی دارد که ان را از دیگر زبان های تابعی متمایز می کند. هم تابعیست هم شی گرا. زبانی استاتیک است ، منتها اجازه می دهد که مثل زبان های داینامیک با آن کار کنیم. سینتکسی دارد که نزدیک به 30 سال است وجود دارد و نخواسته انقلابی ارائه کند. (به قول طراحش ، evolutionary است نه revolutionary). مشکل کتابخانه را حل کرده (استفاده از دات نت). حمایت شرکت مایکروسافت را دارد. هنوز که نسخه ی نهایی اش ارائه نشده ، 3 کتاب داشته (و 3 کتاب هم در راهند) و شرکت های زیادی دارند در محصولاتشان از آن استفاده می کنند. مثل Haskell کاملا lazy نیست ، منتها برای این کار کلمه ی کلیدی مخصوص دارد. مثل Erlang کاملا بر اساس مدل message-passing کار نمی کند ، منتها هم مدل shared memory و هم مدل MP را پشتیبانی می کند. کد موجزی دارد که باعث می شود productivity برنامه نویس بالا رفته و درصد سیگنال به نویز (نقطه ویرگول ، آکولاد ، بلاک ها ، type identifier و ...) بالاتر رود (این رامدیون استفاده از Hindley–Milner[3] (http://www.barnamenevis.org/forum/#_edn3) است)

همانطور که خالق این زبان در مصاحبه هاش گفته ، قرار نیست این زبان جایگزین وی بی یا سی شارپ بشود. در واقع هنوز هم برای برنامه های تجاری[4] (http://www.barnamenevis.org/forum/#_edn4) و GUI و برنامه های تحت وب و ... زبان های فعلی مناسب ترند (نه این که F# قادر به انجام این کارها نباشد)

موارد کاربرد F# :


برنامه هایی که قرار است به صورت موازی روی چند هسته (یا سی پی یو) اجرا شوند
برنامه هایی که با حجم وسیعی از داده ها سر و کار دارند (data analysis)
برنامه های محاسباتی و ریاضی و آماری و ...


و اما در مورد concurrency و عصر جدید (پردازنده های چند هسته ای) که به ما این اجازه را می دهد به صورت واقعی (نه شبیه سازی با thread ها) برنامه هایی بنویسیم که موازی اجرا شوند و اهمیت زبان های تابعی برای این کار (و اصلا این که چطور شد پس از 50 سال توجه عمومی شرکت ها و برنامه نویسا و ... به این زبان ها جلب شده):

دو مدل غالب برای برنامه نویسی موازی داریم: مدل حافظه ی مشترک[5] (http://www.barnamenevis.org/forum/#_edn5) و ارسال پیام[6] (http://www.barnamenevis.org/forum/#_edn6). در مدل حافظه ی مشترک (مدل غالب تر!) به خاطر دسترسی همزمان چند ریسمان/فرایند/پردازنده به قسمتی از حافظه ، مشکلات زیادی مثل race condition و deadlock و synchronization و ... به وجود می آید و همواره باید مراقب کدمان باشیم که همین امر ، برنامه نویسی در این مدل را سخت می کند. در زبان های تابعی به طور پیش فرض ما متغیر نداریم و همه چیز تغییرناپذیر (immutable) است، بنابراین تغییر مقدار بی معنی است. از طرفی در این زبان ها از ساختار هایی مثل حلقه (که تقدم و تاخر را به وجود می آورند) کمتر استفاده شده و مدل برنامه نویسی declarative است؛ بنابراین امکان موازی شدن به صورت خودکار[7] (http://www.barnamenevis.org/forum/#_edn7) (توسط کامپایلر و رانتایم. مثل Parallel LINQ[8] (http://www.barnamenevis.org/forum/#_edn8)) بیشتر شده و کدنویسی به این منظور هم راحت تر می شود. (در زبانی مثل C++‎‎‎ هم این کار قابل انجام است ، منتها زمان زیادی صرف کارهای دستی و مراقب کد بودن و ... می شود که در نهایت هم باگ هایی در برنامه وجود خواهد داشت که پیدا کردنشان خیلی سخت است). این مدل مثل SQL است. شما فقط کوئری را می نویسید و موازی سازی و ... به عهده ی SQL engine هست. ویژگی immutability بزرگ ترین وجه تمایز زبان های تابعی از دیگر زبان هاست. البته باز هم در اینجا F# با استفاده از کلمه ی کلیدی mutable اجازه می دهد که بتوانیم مقدار یک شی را عوض کنیم.

در زیر قطعه کدهایی از زبان F# را همراه با مشابهش در سی شارپ (یا سی پلاس پلاس) قرار می دهم: (هدف نشان دادن برتری زبانی به دیگری نیست ، فقط می خواهم مقایسه ای بین ظاهر و مدل برنامه نویسی صورت بگیرد )

محاسبه ی فاکتوریل یک عدد:

سی شارپ:


class Program
{
public int factorial(int n)
{
if (n < 2)
return 1;
else
return n * factorial(n - 1);
}
}



F#:



let rec factorial n = if n < 2 then 1 else n * factorial (n-1)


Currying:



using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
delegate int myAddDelegate(int a, int b);
delegate int mySecondDelegate(int a);

static void Main()
{
myAddDelegate add = delegate(int a, int b) { return a + b; };
int x = add(10, 20);
mySecondDelegate add10 = delegate(int a) { return add(a, 10); };
int y = add10(20);
}
}



F#:


let add x y = x + y
let add10 x = add x 10
let x = add 10 20
let y = add10 20



ایجاد یک Windows Application ساده:

سی شارپ:



using System.Windows.Forms;

class MyForm : Form
{
private Button btn;

public MyForm()
{
btn = new Button();
btn.Text = "Click me";
btn.BackColor = System.Drawing.Color.Red;
this.Controls.Add(btn);
this.Text = "Hello";
btn.Location = new System.Drawing.Point(50, 50);
this.TopMost = true;
btn.Click += delegate(object sender, System.EventArgs e) { MessageBox.Show("Hello World"); };
}

static void Main()
{
Application.Run(new MyForm());
}
}


F#:



#light
open System.Windows.Forms
let frm = new Form(Text = "Hello")
let btn = new Button(Text = "Click me", BackColor = System.Drawing.Color.Red)
frm.Controls.Add(btn)
btn.Location <- new System.Drawing.Point(50,50)
btn.Click.Add(fun args -> MessageBox.Show("Hello World") |> ignore)
frm.Show()
frm.TopMost <- true



تولید و چاپ اعداد بین 1000000 تا 1002000 به طور موازی (با استفاده از asynchronous workflow ها که از ویژگی های منحصر به فرد زبان F# هست – کلمه ی کلیدی async) (مثال از ویکی پدیا)



let is_prime n =
{2 .. n-1} |> Seq.exists (fun x -> n % x = 0) |> not

let primeAsync n =
async { return (n, is_prime n) }

let primes m n =
{m .. n}
|> Seq.map primeAsync
|> Async.Parallel
|> Async.Run
|> Array.filter snd
|> Array.map fst

primes 1000000 1002000
|> Array.iter (printfn "%d")



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



منابع و مطالعه بیشتر:

این مقاله را به صورت مستقیم از جایی ترجمه نکردم و حاصل تجربه و مطالعات پراکنده ام است.

وبسایت رسمی F# : http://research.microsoft.com/fsharp/fsharp.aspx

فروم F# : http://cs.hubfs.net/forums

وبلاگ Don Syme : http://blogs.msdn.com/dsyme

مدخل ویکی پدیا برای این زبان: http://en.wikipedia.org/wiki/F_Sharp_programming_language

کتب منشتر شده برای این زبان:


Foundations of F# نوشته یRobert Pickering انتشارات Apress
Expert F# نوشته ی Don Syme ، Adam Granicz و Antonio Cisternino انتشارات Apress
F# for Scientists نوشته ی Jon Harrop انتشارات Wiley


(کتاب های Programming F# ، Real World Functional Programming و F# in a Nutshell هم قرار است امسال عرضه شوند)

دربارۀ نویسنده: مهندس نرم افزار. حدود 6 ساله که برنامه نویسی می کنم و خارج از وقت کاریم (که مربوط به امنیت نرم افزار و برنامه نویسی سیستمی میشه) به علایقم (یادگیری زبان های جدید ، زبان های تابعی ، پردازش موازی ، شنا و تماشای فیلم) می پردازم. در حال حاضر بیشترین وقتم صرف مطالعه در مورد Concurrency (Erlang, Parallel FX, Cilk++, …) و زبان های تابعی (F#, Haskell, Scheme/LISP) میشه.


[1] (http://www.barnamenevis.org/forum/#_ednref1) http://en.wikipedia.org/wiki/Alan_Turing


[2] (http://www.barnamenevis.org/forum/#_ednref2) استنباط نوع داده ی یک عبارت یا متغیر بر اساس نوع استفاده از ان


[3] (http://www.barnamenevis.org/forum/#_ednref3) http://en.wikipedia.org/wiki/Type_inference#Hindley.E2.80.93Milner_type_inferen ce_algorithm


[4] (http://www.barnamenevis.org/forum/#_ednref4)Line Of Business


[5] (http://www.barnamenevis.org/forum/#_ednref5) Shared memory


[6] (http://www.barnamenevis.org/forum/#_ednref6) Message passing


[7] (http://www.barnamenevis.org/forum/#_ednref7) Automatic Parallelization


7 http://en.wikipedia.org/wiki/Parallel_FX_Library#PLINQ

آدرس الکترونیکی: mehdi.asgari@yahoo.com

vahid2112
پنج شنبه 05 بهمن 1391, 03:10 صبح
ممنون از زحماتتون
مقاله یا pdf فارسی وجود داره؟

esibarnamenevis
یک شنبه 11 فروردین 1392, 00:26 صبح
اگه امکانش هست به صورت مقاله در بیارید بهتره
با زم ممنون