میراندا (زبان برنامهنویسی)
میراندا یک زبان برنامهسازی غیر اکید، کاملاً تابعی است که توسط David Turner به عنوان جانشینی برای زبان برنامهسازی قبلی او یعنی SASL و KRC طراحی شده، که از برخی مفاهیم ML و HOPE استفاده میکند. محصولی از شرکت Research Software انگلستان. کلمه 'Miranda' نام تجاری است. این زبان اولین زبان کاملاً تابعی است که مورد حمایت تجاری قرار گرفت.
الگو برنامهنویسی | lazy، برنامهنویسی تابعی، برنامهنویسی اعلانی |
---|---|
طراحی شده توسط | David Turner |
توسعهدهنده | Research Software Ltd |
ظهوریافته در | ۱۹۸۵ |
وابستگی زیاد و کم به نوع، static | |
وبگاه | |
پیادهسازیهای بزرگ | |
Miranda | |
متأثر از | |
KRC، امال (زبان برنامهنویسی)، SASL، Hope | |
تأثیر گذاشته بر | |
Clean، هسکل (زبان برنامهنویسی) |
راه حل اکثر مسائل نمونه در Miranda سادهتر و خلاصه تر از راه حلهای زبانهای برنامهسازی دیگر است به استثنای زبان APL و مانند اکثر زبانهای برنامهسازی تابعی دیگر کاربران آن معتقدند که این زبان امکان ایجاد برنامههای قابل اعتمادتری را با زمان ایجاد کمتری نسبت به زبانهای امری که قبلاً استفاده میکردهاند فراهم میکند.
خلاصه
Miranda یک زبان کند و کاملاً تابعی است. به این معنی که این زبان اثرات جانبی و خواص برنامهنویسی امری را ندارد. یک برنامه به زبان Miranda(که به عنوان Script شناخته میشود) مجموعهای از معادلات میباشد که توابع مختلف ریاضی و انواع دادههای جبری را تعریف میکند. کلمه مجموعه در اینجا مهم است: بهطور کل ترتیب معادلات مهم نیست و برای استفاده از موجودیتها الزامی در تعریف پیشاپیش آنها وجود ندارد.
از آنجایی که الگوریتم تجزیه به صورت هوشمند از آرایش متن (توگذاری) استفاده میکند، به ندارت پیش میآید که استفاده از براکت لازم باشد و استفاده از پایان دهنده به دستورها نیز لازم نیست. این خصیصه که از ISWIM الگو برداری شده در occam و Haskell نیز مورد استفاده قرار گرفت و بعدها نیز توسط Python به شهرت رسید.
توضیحات در اسکریپتهای عادی توسط کاراکتر || ارائه شد طوریکه تا انتهای خط ادامه مییابد. قرارداد دیگر برای توضیحات حالتی بود که روی کل سند تحت عنوان «اسکریپت باسواد» تأثیر میگذاشت، به صورتی که هر خطی توضیحات در نظر گرفته میشد مگر اینکه با کاراکتر> شروع میشد.
پایه Miranda انواع char، num و bool میباشند. یک رشته کاراکتری بهطور ساده لیستی از کاراکترهاست، در حالی که نوع num بهطور داخلی بین دو فرم تبدیل میشود: اعداد صحیح با دقت دلخواه (به عبارت دیگر اعداد بزرگ) فرم پیش فرض، و در صورت لزوم مقادیر معمول ممیز شناور. چندتاییها همانند رکوردها در زبانهای شبه پاسکال دنبالهای از عناصر مختلط بالقوه هستند، و توسط پرانتزها نوشته میشوند:
this_employee = («Folland, Mary», ۱۰۵۶۰, False, ۳۵)
week_days = ["Mon","Tue","Wed","Thur","Fri"]
در عوض لیستها رایجترین ساختار دادهای مورد استفاده در Miranda میباشند. لیستها توسط کروشهها نوشته میشوند و عناصر آنها توسط کاما از هم جدا میشوند. عناصر لیستها همگی باید از یک نوع باشند:
week_days = ["Mon","Tue","Wed","Thur","Fri"]
اتصال لیستها توسط ++، تفاضل آنها توسط --، ایجاد آنها توسط :، اندازه آنها توسط # و اندسی دهی آنها توسط ! انجام میشود بنابراین:
days = week_days ++ ["Sat","Sun"]
days = "Nil":days
days!۰ ? "Nil"
days = days -- ["Nil"]
#days ? ۷
چند راه سریع برای ایجاد لیستها نیز وجود دارد:.. برای لیستهایی به کار میرود که عناصر آنها سریهای ریاضی اند و امکان داشتن گام افزایشی غیر از یک را نیز برای آنها فراهم کرده:
fac n = product [۱..n]
odd_sum = sum [۱٬۳..۱۰۰]
رایجترین و قویترین تسهیلات ایجاد لیستها در Miranda توسط «list comperhension»ها ارائه میشود (که قبلاً تحت عنوان عبارتهای ZF شناخته میشدند)، که به دو صورت عمده استفاده میشود: عبارتی که به دنبالهای از جملهها اعمال میشود:
squares = [ n * n | n <- [۱..] ]
که به این صورت خوانده میشود: لیستی از مربعهای n که n عضوی از اعداد صحیح مثبت است.
و به صورت سریهای بازگشتی:
powers_of_۲ = [ n | n <- ۱, ۲*n.. ]
همانطور که در این دو مثال میبینیم Miranda امکان داشتن لیستهایی با طول بینهایت را میدهد، که سادهترین مثال لیست اعداد صحیح مثبت است: [۱..].
علامتگذاری اجرای توابع به سادگی توسط کنار هم قرار دادن انجام میشود مثل SIN X. در Miranda همانند اکثر زبانهای کاملاً تابعی دیگر توابع از نوع first-class (سطح بالا) میباشند که این به این معنی است که توابع میتوانند به عنوان پارامتر به توابع دیگر ارسال شوند، به عنوان نتیجه بازگردتنده شوند یا به عنوان عناصر ساختارهای دادهای منظور شوند، و نکته مهم دیگر این است که توابعی که دو یا بیشتر پارامتر دارند میتوانند «partially parameterised» (تا حدودی معیّن) بشوند یا به عبارتی با تعداد کمتری از پارامترهایشان فراخوانی شوند. این کار تابعی میدهد که در صورت تعیین شدن باقی پارامترها نتیجه نهایی را میدهد. به عنوان مثال:
add a b = a + b
increment = add ۱
این مثال تابعی به نام increment ایجاد میکند که مقدار یک را به آرگمانش اضافه خواهد کرد. در واقع add ۴ ۷ تابع دو پارامتری add را میگیرد آن را به ۴ اعمال میکند و یک تابع تک پارامتری میگیرد که آرگومانش را به ۴ خواهد افزود سپس آن را به ۷ اعمال میکند.
هر تابعی با دو پارامتر میتواند به یک عملگر میانوند تبدیل شود(برای مثال در تابع بالا، جمله $add تا حدودی به عملگر + شباهت دارد) و هر تابع میانوندی که دو پارامتر میگیرد میتونه به تابع معادلش تبدیل بشه. بنابراین:
increment = (+) ۱
راهی ساده برای ایجاد تابعی است که مقدار یک را به آرگومانش اضافه میکند. بهطور مشابه در:
half = (/ ۲)
reciprocal = (۱ /)
دو تابع یک پارامتری ایجاد میشوند، مفسر در هر دو حالت بالا میفهمد که کدام یک از دو پارامتر عملگر تقسیم ارسال شدهاند. مثلاً در حالت اول تابع حاصل همواره آرگومان خود را نصف خواهد کرد.
با وجود اینکه Miranda یک زبان برنامهسازی با انواع قوی است (strongly-typed)، بر تعیین نوع به صورت صریح پافشاری زیادی ندارد. در صورتی که نوع یک تابع به صورت صریح مشخص نشود مفسر اون رو با توجه به پارامترهای تابع و اینکه آنها در تابع به چه صورت مورد استفاده قرار گرفتهاند استنتاج میکنه. علاوه بر انواع پایه (char، num، bool) این زبان یک نوع "anything" نیز دارد و برای مواقعی استفاده میشود که نوع پارامترها مهم نباشد، مثلاً در معکوس کردن یک لیست.
rev [] = []
rev (a:x) = rev x ++ [a]
که میتونه به لیستی با هر نوع از عناصر اعمال بشه، در صورتی که اعلان نوع آن به صورت صریح به صورت زیر خواهد بود:
rev :: [*] -> [*]
نهایتاً این که این زبان مکانیزمهایی برای ایجاد و مدیریت ماژولهای برنامه، ای را داراست که توابع داخلی آنها از دید برنامههایی که این ماژولها را فرا میخوانند پوشیدهاست.
کدهای نمونه
اسکریپت Mirandی زیر مجموعه همه زیر مجموعههای یک مجموعه از اعداد را تعیین میکند.
subsets [] =
subsets (x:xs) = [[x] ++ y | y <- ys] ++ ys
where ys = subsets xs
و این یک اسکریپت با سواد برای تابع prime است که لیست همه اعداد اول را تعیین میکند.
> || The infinite list of all prime numbers, by the sieve of Eratosthenes.
The list of potential prime numbers starts as all integers from ۲ onwards;
as each prime is returned, all the following numbers that can exactly be
divided by it are filtered out of the list of candidates.
> primes = sieve [۲..]
> sieve (p:x) = p: sieve [n | n <- x; n mod p ~= ۰]