نحو زبان برنامهنویسی سلام بیشتر برای خوانده شدن طراحی شده تا نوشته شدن: بلوکها با دونقطه باز و با پایان (end) بسته میشوند، متغیرها با := تعریف میشوند و تا با ناپایا (mut) علامت نخورند تغییرناپذیرند، تابعها با برگشت (ret) مقدار برمیگردانند و منطق با واژههای و، یا و وارونه (and، or، not) نوشته میشود. هدف کدی است که نوآموز بتواند بلند بخواند، برنامهنویس باتجربه بتواند سریع از رویش بگذرد، و یک به یک بر املای دوم، یعنی املای فارسی، نگاشت شود، بی آنکه گونههای ایستا، تطبیق الگو یا کنترل سطح پایین از دست برود. هر جا سلام ناچار بوده میان کوتاهی و روشنی انتخاب کند، معمولاً روشنی را برگزیده، و هر جا میان انعطاف و یک راه بدیهی، معمولاً یک راه بدیهی را.
این مقاله تصمیمهای اصلی نحوی را مرور میکند، آنها را در برنامههای قابل اجرا نشان میدهد، با پایتون، Go، Ruby و Lua مقایسه میکند و صادقانه میگوید هر تصمیم چه هزینهای دارد. نمونهها به سلام فارسی نوشته شدهاند و معادل انگلیسی هر واژهی کلیدی کنارش آمده است.
اصول پشت نحو زبان سلام
چهار ایده بیشتر نحو سلام را توضیح میدهد:
- بلوکها باید دیده شوند. باید بتوانید پایان یک بلوک را ببینید، بی آنکه فاصله بشمارید یا آکولادها را جفت کنید.
- پیشفرض باید انتخاب امن باشد. مقدارها تا خودتان نگویید عوض نمیشوند؛ شرطها باید منطقی واقعی باشند؛ عددها بیصدا معنای «درست» نمیدهند.
- یک راه بدیهی. هر جا دو شکل نوشتن همان کار را انجام دهند، سلام اغلب فقط یکی را مجاز میداند و دیگری را خطایی همراه با اصلاح میکند.
- دو املا، یک دستور زبان. هر ساخت باید هم به انگلیسی و هم به فارسی طبیعی خوانده شود، چون املای فارسی نگاشت توکن به توکن املای انگلیسی است (نگاه کنید به یک زبان، دو خط). این قاعده نحوی را که به ترتیب کلمات انگلیسی یا به نمادهایی که در متن راست به چپ بد رفتار میکنند تکیه دارد کنار میگذارد.
بلوکها: دونقطه برای باز کردن، پایان برای بستن
هر بلوک در سلام با : باز و با پایان بسته میشود: تابع، شرط، حلقه، ساختار، جداشمار و شاخههای همخوانی. بلوک کوتاه میتواند در یک سطر بیاید.
تابع علامت عدد(ن: صحیح): رشته:
اگر ن < ۰: برگشت "منفی" پایان
اگر ن == ۰: برگشت "صفر" پایان
برگشت "مثبت"
پایان
تابع ریشه:
هر ن در [-۴، ۰، ۹]:
سرچاپ ن، علامت عدد(ن)
پایان
پایاناین شیوه میان پایتون و Ruby مینشیند. پایتون بلوک را با دونقطه باز و با کم کردن تورفتگی میبندد؛ تمیز است، اما پایان بلوک نامرئی میشود و کد کپیشده شکننده. Ruby و Lua بلوک را با end میبندند، اما به چند شکل مختلف باز میکنند (do، then یا هیچ). سلام دونقطه را از پایتون و end را از Ruby و Lua گرفته و همین جفت را همهجا به کار میبرد. تورفتگی قراردادی است و salam format آن را یکدست میکند، اما معنایی ندارد، پس بلوکی که در عمق نادرست جاگذاری شود باز هم همانطور تجزیه میشود.
آکولاد برای بلوک به کار نمیرود؛ در سلام { } مال ساختارهای لفظی (نقطه { ایکس = ۱ }) و ظرفهای خالی لفظی است. املای انگلیسی همین شکل را دارد: : و end.
تعریف متغیر: :=، ناپایا و پایا
پایا بیشینه_کاربر := ۱۰۰
تابع ریشه:
نام := "سارا"
ناپایا بازدید := ۰
بازدید++
بازدید += ۲
نسبت := بازدید برگردان اعشار۶۴ / بیشینه_کاربر
عدد بزرگ := ۳۰۰۰۰۰۰۰۰۰ برگردان صحیح۶۴
سرچاپ نام، بازدید، نسبت، عدد بزرگ
پایان:= مثل Go متغیر را تعریف و گونهاش را استنتاج میکند. اما برخلاف Go، نتیجه تغییرناپذیر است: نام هرگز دوباره مقداردهی نمیشود و تلاش برای این کار خطای کامپایل است، نه هشدار:
خطا[خطا۰۱۳]: نمیتوان متغیر تغییرناپذیر 'سقف' را دوباره مقداردهی کرد؛ برای این کار آن را 'ناپایا' تعریف کنید، یا بهجای آن به عناصر یا فیلدهایش مقدار دهیدناپایا (mut) تغییر را صریحاً اجازه میدهد؛ همان ایدهی let mut در Rust یا var در Swift. خواننده میتواند مطمئن باشد نامی که ناپایا ندارد مقدارش را نگه میدارد، و همین دنبال کردن تابعهای بلند را بسیار سادهتر میکند.
برای متغیر محلی شکل ک: صحیح = ۵ وجود ندارد. سلام زمانی تعریف با گونهی صریح داشت و آن را حذف کرد: وقتی گونهای جز گونهی استنتاجشده میخواهید، برگردان (as) مینویسید، مثل ۳۰۰۰۰۰۰۰۰۰ برگردان صحیح۶۴ در برنامهی بالا. این کار دقیقاً یک راه برای تعریف متغیر محلی باقی میگذارد. نوشتن گونه هر جا که اطلاعاتی میدهد که قابل استنتاج نیست باقی مانده است: پارامترها، گونهی برگشتی و فیلدهای ساختار.
واژههای کلیدی کوتاه برای کارهای پرتکرار
در املای انگلیسی واژههایی که بیشتر تایپ میشوند کوتاهاند: func، ret، mut، pub، end. واژههایی که کمتر تایپ میشوند کامل نوشته میشوند: struct، enum، interface، defer، match. این همان بدهبستانی است که Go با func انجام داد، و دلیل اینکه return در سلام ret است: در یک تابع معمولی چند بار تکرار میشود. املای فارسی همین واژهها را با معادلهای آشنای فارسی مینویسد: تابع، برگشت، ناپایا، همگانی، پایان، و برای دستهی دوم ساختار، جداشمار، میانجی، دیرکن، همخوان.
سرچاپ و چاپ (println و print) دستورند، نه فراخوانی تابع، و آرگومانهایشان را بدون پرانتز میگیرند: سرچاپ نام، بازدید. آرگومانها با فاصله کنار هم چاپ میشوند، همان چیزی که نوآموز از نخستین برنامهاش انتظار دارد و یک سطر اشکالزدایی معمولاً لازم دارد.
حلقهها: تا، تکرار و هر
سلام سه حلقه دارد و نه while دارد و نه for به سبک C:
تابع ریشه:
ناپایا ن := ۲۷
ناپایا گامها := ۰
تا ن != ۱:
ن = ن % ۲ == ۰ ? ن / ۲ : ۳ * ن + ۱
گامها++
پایان
سرچاپ "گامهای کولاتز برای ۲۷:"، گامها
تکرار ۲ در ای:
سرچاپ "تکرار"، ای
پایان
تکرار ۱۰ تا ۰ هر ۵ در ای:
سرچاپ "نزولی"، ای
پایان
هر ای، نام در ["سارا"، "علی"]:
سرچاپ ای، نام
پایان
پایانتکرار(repeat) شمارش را پوشش میدهد:تکرار ۳سه بار اجرا میشود،تکرار ن در ایاز صفر میشمارد،تکرار ۱ تا ۵دو سر بازه را شامل میشود وهرگام را تعیین میکند. جهت را مرزها تعیین میکنند، پستکرار ۱۰ تا ۰رو به پایین میشمارد.هر(each) آرایه، وکتور، نگاشت، رشته و گونههای خود شما را پیمایش میکند، با اندیس یا کلید اختیاری.تا(until) حلقهی عمومی است و تنها تصمیم این فهرست که آدمها سرش زمین میخورند:until c:تا وقتیcدرست است اجرا میشود. واژهی انگلیسی خلاف این را القا میکند. املای فارسیاش،تا، بهطور طبیعی «تا وقتی که» معنا میدهد، پس در فارسی همین واژهی کلیدی درست خوانده میشود. مقالهی طراحی برای فارسی این بدهبستان را توضیح میدهد؛ توصیهی عملی این است کهuntilرا در کد انگلیسی «while» بخوانید.
حذف حلقهی سهبخشی for در C یک منبع کلاسیک خطای یکیکمیکیزیاد (Off-by-one) را از میان برمیدارد و نیت هر حلقه را در نخستین واژهاش نشان میدهد. درس حلقهها همهی شکلها را پوشش میدهد.
همخوان و ترابرد (match و switch)
سلام جز اگر دو ساخت انشعاب دیگر هم دارد و این دو کارهای متفاوتی انجام میدهند.
جداشمار شکل:
دایره(شعاع: اعشار۶۴)
مستطیل(پهنا: اعشار۶۴، بلندی: اعشار۶۴)
پایان
تابع توصیف(ش: شکل): رشته:
برگشت همخوان ش:
دایره(ر): "دایره، شعاع " + ر پایان
مستطیل(پ، ب) اگر پ == ب: "مربع، ضلع " + پ پایان
مستطیل(پ، ب): "مستطیل، " + پ + " در " + ب پایان
پایان
پایان
تابع رتبه(نمره: صحیح): رشته:
ترابرد نمره:
۹۰ تا ۱۰۰: برگشت "الف" پایان
۷۵ تا ۸۹: برگشت "ب" پایان
وگرنه: برگشت "ج" پایان
پایان
برگشت "?"
پایان
تابع ریشه:
شکلها := [شکل.دایره(۱.۵)، شکل.مستطیل(۲.۰، ۲.۰)، شکل.مستطیل(۳.۰، ۱.۰)]
هر ش در شکلها:
سرچاپ توصیف(ش)
پایان
هر نمره در [۹۵، ۸۰، ۴۰]:
سرچاپ نمره، رتبه(نمره)
پایان
پایانهمخوان (match) یک عبارت است: مقدار تولید میکند، جداشمارهایی را که داده حمل میکنند باز میکند، نگهبان (اگر پ == ب) را پشتیبانی میکند و باید همهی حالتها را پوشش دهد، وگرنه برنامه کامپایل نمیشود. این ساخت برای کار با داده است، به روح match در Rust یا switch در Swift.
ترابرد (switch) دستوری برای جریان کنترل روی مقدارهای ساده است، با بازه (۹۰ تا ۱۰۰)، فهرست جداشده با ویرگول و برچسبهای مقایسهای مثل > 60. ریزش به شاخهی بعد (Fallthrough) به سبک C دارد، مگر آنکه بشکن یا برگشت بنویسید؛ این برای کد منتقلشده از زبانهای دیگر مفید و دامی شناختهشده است، پس یک بررسی اختیاری (Lint) زنجیرههای بلند اگر را که باید ترابرد باشند علامت میزند. هر دو همان شکل برچسب: ... پایان بقیهی بلوکها را دارند. درس همخوان و درس جداشمارها جلوتر میروند.
نامهای فاصلهدار در زبان سلام
نام در سلام میتواند فاصله داشته باشد: علامت عدد، جمع ردیف، آخر هفته است. در این صورت فراخوانی مثل یک عبارت خوانده میشود: علامت عدد(ن). این امکان بیشتر برای فارسی وجود دارد، که بسیاری از مفهومها در آن بهطور طبیعی دوکلمهایاند و چسباندنشان نادرست به نظر میرسد، اما در انگلیسی هم کار میکند (sign of، line total).
دو قاعده آن را بیابهام نگه میدارد. کلمههای یک نام نمیتوانند واژهی کلیدی باشند (فاصله تا مبدا کار نمیکند، چون تا واژهی کلیدی است؛ در انگلیسی هم distance to origin به خاطر to همینطور)، و نامهای پایا (const) باید یککلمهای باشند. برخی تیمها در کد انگلیسی همچنان snake_case را ترجیح میدهند و این هم اشکالی ندارد؛ زیرخط نویسهای معمولی است.
واژه برای منطق، و یک راه برای بهروز کردن مقدار
منطق با واژه نوشته میشود: و، یا، وارونه (در انگلیسی and، or، not). نمادهای &&، || و ! عملگر سلام نیستند و کامپایلر همین را میگوید و واژهی درست را نام میبرد:
خطا: '&&' عملگر سلام نیست؛ به جای آن 'و' بنویسیدشرطها باید منطقی واقعی باشند. اگر ن: با یک ن صحیح خطای E021 است («شرط 'اگر' باید بولی باشد»)، پس چیزی به نام «درستنمایی» مقدارها وجود ندارد که لازم باشد به خاطر بسپارید. مقایسهها را هم میشود با واژه نوشت (بزرگتر، کوچکتر، برابر)، که در فارسی اهمیت دارد، چون < و > در متن راست به چپ قرینه نمایش داده میشوند.
سلام دربارهی بهروز کردن یک متغیر بر حسب خودش سختگیر است. ک = ک + ۱ خطایی همراه با اصلاح است:
خطا[خطا۱۶۲]: 'شمار = شمار + ۱' مجاز نیست: بنویسید 'شمار++'قاعده یک املا برای هر عملیات است: ک++ و ک-- برای گام یک، و ک += ن و همخانوادههایش برای بقیه. یک روز ایرادگیرانه به نظر میرسد و بعد از ذهن میرود؛ سودش این است که هر بهروزرسانی در کل کد یک شکل دارد و بازبینی و جستوجوی کد سادهتر میشود. متغیر بیاستفاده هم بهجای هشدار، خطاست.
سلام کنار پایتون، Go، Ruby و Lua
یک تابع، جمع عددهای زوج یک فهرست، در پنج زبان. پایتون:
def sum_even(numbers):
total = 0
for n in numbers:
if n % 2 == 0:
total += n
return totalGo:
func sumEven(numbers []int) int {
total := 0
for _, n := range numbers {
if n%2 == 0 {
total += n
}
}
return total
}Ruby:
def sum_even(numbers)
total = 0
numbers.each do |n|
total += n if n.even?
end
total
endLua:
local function sum_even(numbers)
local total = 0
for _, n in ipairs(numbers) do
if n % 2 == 0 then
total = total + n
end
end
return total
endسلام:
تابع جمع زوجها(عددها: صحیح[]): صحیح:
ناپایا مجموع := ۰
هر ن در عددها:
اگر ن % ۲ == ۰:
مجموع += ن
پایان
پایان
برگشت مجموع
پایان
تابع ریشه:
سرچاپ جمع زوجها([۱، ۲، ۳، ۴، ۵، ۶])
پایان| ویژگی | پایتون | Go | Ruby | Lua | سلام |
|---|---|---|---|---|---|
| مرز بلوک | دونقطه + تورفتگی | آکولاد | end (با شروعهای گوناگون) | end (do، then) | دونقطه + پایان (end) |
| تعریف متغیر | انتساب | := یا var | انتساب | local | := |
| تغییرناپذیر بهطور پیشفرض | نه | نه | نه | نه | بله، با ناپایا تغییرپذیر |
| گونهی ایستا | راهنمای اختیاری | بله | نه | نه | بله، استنتاجشده |
| شکلهای حلقه | for، while | فقط for | each، while، until | for، while، repeat | هر، تکرار، تا |
| عملگرهای منطقی | and or not | && || ! | هر دو | and or not | و یا وارونه (and or not) |
| تطبیق الگو | match (از ۳٫۱۰) | ندارد | case/in | ندارد | همخوان، با پوشش کامل |
| کامپایل به کد بومی | نه | بله | نه | نه | بله |
نسخهی سلام به پایتون و Lua نزدیکتر خوانده میشود، := و گونههای ایستای Go را نگه میدارد و پایان صریح و تغییرپذیری صریح را اضافه میکند. از نسخهی Ruby، که به بلوکها و برگشت ضمنی تکیه دارد، بلندتر است؛ سلام برگشت صریح را ترجیح میدهد.
نحو سلام چه هزینهای دارد
هر انتخاب بهایی دارد و برخی بهاهای سلام واقعیاند:
untilدر املای انگلیسی یعنی while. واژههای آشنای انگلیسی انتظاری با خود میآورند و این یکی خلاف آن است. رایجترین اشتباه هنگام انتقال کد از زبانهای دیگر همین است؛ املای فارسی،تا، این مشکل را ندارد.پایانپرحرف است. کد با تودرتویی زیاد سطرهایپایانپشت سر هم جمع میکند که پایتون لازمشان نداشت.- سختگیری ساعت اول را کند میکند. خطا برای متغیر بیاستفاده،
ک = ک + ۱و شرط غیرمنطقی تازهکارها را غافلگیر میکند، هرچند هر کدام اصلاح پیشنهادی دارند. - تغییرات پیش از نسخهی ۱٫۰. نحو هنوز بین نسخهها جابهجا میشود: تعریف محلی با گونهی صریح و پیکان
=>لامبدا حذف شدند. کدی که برای نسخهی قدیمیتر نوشته شده ممکن است ویرایش لازم داشته باشد. - نام فاصلهدار غیرمعمول است. ابزارهایی که فرض میکنند شناسه فاصله ندارد، از الگوهای grep تا رنگآمیزهای زبانهای دیگر، دقت بیشتری لازم دارند.
برای همهی قاعدهها درس قاعدهها و درس روشهای خوب را ببینید و برای اینکه نحو چطور از هدفهای زبان بیرون آمد، چرا جهان هنوز به زبانهای برنامهنویسی تازه نیاز دارد را بخوانید.
پرسشهای پرتکرار دربارهی نحو زبان سلام
آیا نحو زبان سلام شبیه پایتون است؟
در روح نزدیک است: دونقطه بلوک را باز میکند، نقطهویرگول در کار نیست، منطق با واژه نوشته میشود و کد از بالا به پایین خوانده میشود. تفاوتها این است که بلوکها با پایان بسته میشوند، گونهها ایستا و استنتاجشدهاند، متغیرها تا ناپایا تعریف نشوند تغییرناپذیرند و کد به فایل اجرایی بومی کامپایل میشود.
آیا سلام آکولاد دارد؟
نه برای بلوکها. هر بلوک با دونقطه باز و با پایان بسته میشود. آکولاد در ساختارهای لفظی مثل نقطه { ایکس = ۱، ایگرگ = ۲ } و ظرفهای خالی لفظی دیده میشود.
چرا سلام بهجای while از until و تا استفاده میکند؟
سلام واژهی کلیدی while ندارد؛ until c: (در فارسی تا c:) تا وقتی c درست است تکرار میشود. املای فارسی، تا، به معنای «تا وقتی که» است و طبیعی خوانده میشود، اما واژهی انگلیسی خلاف معنای معمولش خوانده میشود. آن را «while» بخوانید.
آیا نام متغیر در زبان سلام میتواند فاصله داشته باشد؟
بله. نامهایی مثل جمع ردیف یا آخر هفته است یک شناسهاند و این بهویژه در فارسی کمک میکند. نام چندکلمهای نمیتواند واژهی کلیدی داشته باشد و نام ثابتها باید یککلمهای باشد.