برنامه نویسی به زبان ارلنگ

ارلنگ زبان برنامه نویسی تابعی و همروند است

برنامه نویسی به زبان ارلنگ

ارلنگ زبان برنامه نویسی تابعی و همروند است

برنامه نویسی به زبان ارلنگ

در این وبلاگ مطالب مربوط به ارلنگ و الیکسیر منتشر خواهد شد

۸ مطلب با کلمه‌ی کلیدی «Erlang» ثبت شده است

  • ۰
  • ۰

این مثال محاسبه سود است. برای مثال اگر شما 1500 دلار داشته باشید و سالانه 4.3% سود بگیرید بعد از 4 سال پول شما از طریق فرمول زیر به 1758 خواهد رسید.

A = P(1 + rt)

که در آن r همان نرخ سود و t تعداد سال است و P هم همان پول اولیه شماست. در نوشتن این کد به مشکلی برخوردم و آنهم خواندن نوع اعشاری بود که در کد نحوه آن قابل مشاهده است. نکته دیگر استفاده از دیباگر ارلنگ بود. برای این کار باید debug_info را به نحوه زیر به کد اضافه کنید. کار با دیباگر ارلنگ را در زیر کد توضیح خواهد داد.

-module(ex12).
-export([main/0]).
-compile([debug_info]).

main() ->
	try run()
	catch
		error:_Error -> io:format(
			"Please Enter only Numeric type~n");
		throw:negativeNumber -> io:format(
			"Please Enter only non-zero positive number~n")
	end.

run() ->
	{P,I,Y} = readItems(),
	Total = calc_Investment({P,I,Y}),
	io:fwrite(
		"After ~w years at ~w%, the investment will be worth $~w.",
		[Y,I,Total]).

calc_Investment({P,I,Y}) -> 
	P*(1+(I*Y/100)).
	
readItems() ->
	{ok,[P]} = io:fread(
		"Enter the principal: ","~d"),
	%{ok,[I]} = io:fread(
	%	"Enter the rate of interest: ","~f"),
	{I,_} = string:to_float(string:strip(
			io:get_line("Enter the rate of interest: "), right, $\n)),
	{ok,[Y]} = io:fread(
		"Enter the number of years: ","~d"),
	if
		P =< 0 orelse I =< 0 orelse Y =< 0 -> 
			throw(negativeNumber);
		true -> ok
	end,
	{P,I,Y}.

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

163> c(ex12,debug_info).
{ok,ex12}
164> debugger:start().
{ok,<0.552.0>}
  • مهدی حسینی مقدم
  • ۰
  • ۰

تصمیم گرفتم مثالهای کتاب Exercises for programmer را به زبان ارلنگ انجام دهم و پس اطمینان از درستی آنها، منتشر کنم. مثال اول که بسیار ساده بود. از کاربر اسمش را سوال کنم و عبارت Hello را در ابتدای آن گذاشته و سپس در خروجی چاپ کند.

 کد بشرح زیر است:

-module(ex1).

-export([hello/0]).

hello() ->
    {ok,S} = io:fread("What is your name? ","~s"),
    io:fwrite("Hello ~s~n",[S]).
  • مهدی حسینی مقدم
  • ۰
  • ۰

حتما شما با سری فیبوناچی در دوران دبیرستان آشنا شده‌اید. بطور اختصار سری فیبوناچی از فرمول زیر بدست می‌آید:

f(n) = f(n-1) + f(n-2)

هر عنصر در این سری حاصل جمع دو عنصر ما قبل است. البته مقدار برای n برابر با صفر و یک هر دو یک است. برای نمونه سری زیر، فیبوناچی است:

1,1,2,3,5,8,13,21

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

-module(fib).
-export([fib/1]).

fib(0) -> 0;
fib(1) -> 1;
fib(N) -> fib(N-1) + fib(N-2).

خیلی ساده در نمونه کد بالا یک ماژول به اسم fib تعریف شد. تابعی به همین نام نیز تعریف شد که برای مقدار ورودی 0 و 1 خروجی 1 را بر می گردان. برای سایر موارد درست مانند فرمول ریاضی عمل می‌کند. هرگاه تابعی در درون خود خودش را صدا بزند با آن تابع بازگشتی می‌گویند. برای کامپایل کردن کد بالا ابتدا وارد شل ارلنگ شده و کد مربوط را با روش زیر کامپایل و سپس اجرا می‌کنیم:

1>    c(fib.erl).
{ok,fib}

2>    [fib:fib(1), fib:fib(2), fib:fib(3), fib:fib(4), fib:fib(5), fib:fib(6)].
[1,1,2,3,5,8]

خب بنظر کار ما تمام است. اما تابع تعریف شده مشکلاتی دارد. از آنجایی که برای نمونه (fib(n-1) = fib(n-2) + fib(n-3 پس می توان نتیجه گرفت که مقدار(fib(n-2 دوبار محاسبه می‌شود و این مسئله بار زیادی برروی سیستم می‌گذارد.

راه حال بهتر استفاده از نوع خاصی از توابع بازگشتی است که به آنها tail-recursive گفته می‌شود. شاید بهترین ترجمه برای آن بازگشتی انتهایی باشد. در این توابع باز هم خود تابع صدا زده می‌شود اما به عنوان آخرین عبارت و کنترل هرگز به تابع صدا زننده بر نمی‌گردد. با استفاده از این تعریف تابع بصورت زیر باز تعریف می‌شود:

-module(fib2).
-export([fib/1]).

fib(N) -> fib_iter(N, 0, 1).

fib_iter(0, Result, _Next) -> Result;
fib_iter(Iter, Result, Next) when Iter > 0 -> fib_iter(Iter-1, Next, Result+Next).

برای مقایسه سرعت دو تابع می‌شود از تابع tc در ماژول timer با گونه زیر استفاده کرد. نتیجه برای هر دو تابع قابل مشاهده و مقایسه است.

 

timer:tc(fib, fib, [40]). % {556300, 102334155}

timer:tc(fib2,fib,[40]). %{0, 102334155}

مولفه اول در توپل نشان دهنده زمان اجرا بر مبنای میلی ثانیه است. همانطور که می بینید تفاوت فاحش است.

لازم به ذکر است تا کنون JVM و NET. از بازگشتی انتهایی پشتیبانی نمی‌کنند هرچند بنابه گفته مایکروسافت در سال آینده این قابلیت اضافه خواهد شد.

  • مهدی حسینی مقدم
  • ۰
  • ۰

مدلی که ارلنگ برای همروندی و همزمانی استفاده می کند بر اساس مدل بازیگر (actor model) است. تمام چیزی که برای نوشتن نرم افزار های همروند در ارلنگ نیاز دارید در سه چیز خلاصه می شود: ساخت پروسه، ارسال پیام به پروسه و دریافت و خواندن پروسه ارسال شده می‌باشد. هر پروسه در ارلنگ دارای مفهومی بنام صندوق پستی است. پیام های ارسالی به هر پروسه درون این صندوق ذخیره می شود و پروسه می‌تواند براساس صلاح دید خود پیامهایش را بخواند و یا دور بریزد. برای ساختن پروسه جدید در ارلنگ از روش زیر می‌توان استفاده کرد:

F = fun() -> 2 + 2 end.

spawn(F).

Spawn به عنوان خروجی شناسه پروسه که به آن PID می گویند را بر می‌گرداند. از این PID می‌توان برای ارسال پیام به پروسه استفاده کرد. ارسال پیام به پروسه به عملگر "!" امکان پذیر است.

Pid ! hello.

زمانی که پیام ارسال شد گیرنده با استفاده از receive می تواند مقدار پیام را بخواند. مثال زیر برنامه کوچکی است که منتظر پیام می‌نشیند و حسب نوع و مقدار آن واکنشی را نشان می‌دهد که در این مثال محاسبه‌ی مساحت شکل مورد در خواست است.

-module(calculateGeometry).
-compile(export_all).

calculateArea() ->
	receive
		{rectangle, W, H} -> W * H;
		{circle, R} -> 3.14 * R * R;
		_ -> io:format("We can only calculate area of rectangles or circles.")
	end.

با استفاده از تابع c ماژول را کامپایل کرده و از تابع استفاده می‌کنیم.

c(calculateGeometry).

CalculateArea = spawn(calculateGeometry, calculateArea, []).

CalculateArea ! {circle, 2}.

هر پروسه با استفاده از تابع()self می تواند از شناسه خودش مطلع شود.

 

  • مهدی حسینی مقدم
  • ۰
  • ۰

گاهی اوقات نیاز دارید توابعی را برای استفاده لحظه ای تعریف کنید و یا برای نمونه تابعی را به عنوان متغیر به تابع دیگری بفرستید. برای این منظور در ارلنگ می توانید توابع بی نام تعریف کنید برای این کار مطابق زیر عمل کنید:

Double = fun(X) -> 2 * X end.

در مثال فوق Double  یک متغیر است که تابعی را در خود جا داده است. این تابع بی نام ورودی خود را دوبرابر می کند. می توان از Double مانند تابع معمولی استفاده کرد برای نمونه می توان از Double با ورودی 10 خروجی 20 را گرفت. استفاده از توابع بی نام محدودیتی ندارد و شما می توانید در داخل توابع بی نام از توابع بی نام استفاده کنید. عدد ورودی را در در عدد دیگری ضرب می کند. خروجی تابع اول تابعی است که عمل ظرب را انجام می دهد. خروجی تابع دوم عدد مورد نظر است:

Mult = fun(Times) -> ( fun(X) -> X * Times end ) end.

Triple = Mult(3).

Triple(5).  % 15

کنترل ورودی توابع از طریق گارد:

گاهی اوقات نیاز دارید مقادیر ورودی توابع را چک کنید بدون آنکه وارد تابع شوید. بنابراین در ارلنگ در صورت عدم تطابق به قسمت بعدی تابع جابجا می شوید. برای اینکار از when استفاده می کنیم. یعنی زمانی از این قسمت تابع استفاده کن که شرط مقابل برقرار باشد. به مثال زیر توجه کنید:

max(X, Y) when X > Y -> X;

max(X, Y) -> Y.

تابع بالا بیشینه دو عدد را بر می گرداند. قسمت اول چنانچه X>Y باشد تابع X  را بر می گرداند. چنانچه نبود تابع در قسمت دوم اجرا می شود که Y  را بر می گرداند. مشاهده می کنید که در ارلنگ عملا بجای استفاده از if که در زبان های رایج کاربرد دارد می تواند در قسمت ورودی توابع را بررسی کرد. با عبارت when  و شرط بعدی اش گارد گفته می شود. گارد ها می تواند شامل چند پیش شرط باشند که با ‘,’ از هم جدا می شوند و معنی AND را می دهد.

  • مهدی حسینی مقدم
  • ۰
  • ۰

کدهای زبان برنامه نویسی ارلنگ در درون واحدی بنام ماژول قرار می گیرد تقریبا تمامی توابع در داخل ماژول نوشته می‌شوند. ماژول ها در داخل فایلهایی با پسوند .erl ذخیره می‌شوند. ماژول ها برای اجرا نیاز به کامپایل شدن دارند. لازم به ذکر است فایل های کامپایل شده دارای پسوند .beam می باشند. در مثال زیر تابعی بنام area تعریف شده که بسته به نوع ورودی مساحت شکل مورد نظر را محاسبه می کند.

-module(geometry).

-export([area/1]).

area({rectangle, Width, Height}) -> Width*Height;

area({circle, R}) -> 3.14 * R * R.

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

area({rectangle, Width, Height}) -> Width*Height;

area({circle, R}) -> 3.14 * R * R;

area(_) -> error.

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

فایل فوق بنام geometry.erl ذخیره می گردد. برای کامپایل کردن آن کافی است وارد محیط ارلنگ شده و با استفاده از دستور زیر فایل را کامپایل کنیم:

c(geometry).

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

geometry:area({rectangle, 10, 50}).

geometry:area({circle, 2}).

به ترتیب باید 500 و 12.56 را بعنوان جواب دریافت کنید.  

چنانچه شما دانشی در زمینه زبانهای برنامه نویسی شی گرا داشته باشید با نوع داده‌ و توابع عمومی و خصوصی آشنا هستید. توابع عمومی توابعی هستند که در بیرون از کلاس قابل دسترسی هستند حال آنکه توابع خصوصی تنها در داخل کلاس می توانند مورد استفاده قرار گیرند. چنین محدود سازی در ارلنگ با کمک export صورت می گیرد. در قسمت export شما لیستی از توابعی را که مایلید از بیرون قابل اجرا باشند را وارد می کنید. توابع بصورت نام / تعداد ورودی نوشته می شوند. از آنجایی که تابع area تنها یک ورودی می گیرد نام کامل آن بصورت area/1 خواهد بود.

  • مهدی حسینی مقدم
  • ۰
  • ۰

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

% this is comment

ارلنگ دارای محیطی بنام REPL است که چیزی شبیه شل در لینوکس و محیط کامند در ویندوز است. برای استفاده از آن در لینوکس فرمان erl را تایپ کنید. در ویندوز کافی است این برنامه را از شاخه برنامه های خود اجرا نمائید.

متغیر ها در زبان ارلنگ با حروف بزرگ آغاز می شود. در ارلنگ در پایان هر عبارت باید "." گذاشت. برای مثال خط زیر مقدار 7 را به متغیر X نسبت می دهد:

X = 7.

شما به هر متغیر می توانید تنها یکبار مقدار بدهید، این نخستین تفاوت برنامه نویسی فانکشنال با زبانهای شی گرا می باشد. برای مثال چنانچه شما بخواهید مقدار 9 را به X  بدهید پیغام خطای زیر را دریافت خواهید کرد:

 

** exception error: no match of right hand side value 9

برای مقدار دهی نیاز به مشخص کرد نوع داده نیست بنابرین شما می توانید هر مقداری خواستید به هر متغیر بدهید برای مثال می توانید مقدار اعشاری وارد نمائید.

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

Y = hello.

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

Point = {7,8}.

قابلیت زیبای ارلنگ استخراج مقادیر از عبارات است برای مثال شما می توانید با استفاده از دستور زیر مقادیر داخل Point را در متغیر های جدید قرار دهید:

{X,Y} = Point.

با انجام این کار X برابر 7 و Y برابر 8 خواهد بود.

لیست ها آرایه هایی از مغادیر مختلف هستند. برای ایجاد یک لیست کافیست از ] استفاده کنید. برای مثال مانند زیر عمل کنید:

L = [1,2,3,4,5]

با استفاده از | شما می توانید راس یک لیست را از باقی آن جدا کنید برای مثال:

[H|T] = L.

که در این صورت خواهیم داشت:

H = 1 , T = [2,3,4,5]

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

[72, 101, 108, 108, 111] = "Hello".

 

  • مهدی حسینی مقدم
  • ۰
  • ۰

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

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

ابتدا ویم را با استفاده از فرمان زیر نصب کنید:

sudo apt-get install vim

ویرایشگر ویم قابلیت افزدون ماژول های مختلف را دارد برای این منظور ابتدا نیاز است یک ماژول خاص جهت افزودن سایر ماژول های برنامه نویسی به آن اضافه کنیم. انتخاب من pathogen است. برای نصب آن فرامین زیر اجرا کنید:

mkdir -p ~/.vim/autoload ~/.vim/bundle && \

curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim

سپس فایل vimrc. را که در پوشه خانه شما قرار دارد را ویرایش کنید. برای رفتن به خانه از فرمان cd ~ استفاده کنید. چنانچه این فایل موجود نبود آن را ایجاد کنید و سپس محتویات زیر را آن را قرار دهید:

execute pathogen#infect()

syntax on

filetype plugin indent on

حالا همه چیز آماده است برای نصب ماژول ارلنگ. برای این منظور فرامین زیر را اجرا کنید:

cd ~/.vim/bundle && \

git clone https://github.com/jimenezrick/vimerl.git

حال هر زمان شما فایلی را با پسوند erl باز کنید VIM کلمات و علائم زبان ارلنگ را با رنگ منحصر بفرد نشان می دهد.

  • مهدی حسینی مقدم