در مورد الگوریتم ماشین حساب ما استفاده از یک بافر برای گرفتن عبارت بطور کامل و سپس تجزیه کردن اجزای (Parse) آن از لحاظ فنی غیر ممکن نیست و تنها بدلیل صورت مسئله قادر به انجام آن نیستیم.
اما تصور کنید که اگر قرار بود مرورگرهای وب (Web Browsers) ابتدا تمام محتوای یک صفحه را بخواندند و سپس آن را تجزیه کرده و نمایش دهند چه مقدار زمان کاربر و سرویس دهنده وب به هدر میرفت و ترافیک بیهودهای برروی خطوط ارتباطی حاصل میشد (در اکثر موارد ما با دیدن تنها چند خط از یک صفحه به صفحه دیگری میرویم(.
مقدمه
یک الگوریتم مجوعهی متناهی از دستورالعمل های خوش تعریف برای انجام یک عمل است که با داشتن یک حالت اولیه به حالت پایانی مشخص و متناظری خواهد رسید.
(با استدلالی ( heuristic )مقایسه شود(
مفهوم یک الگوریتم معمولاً با مثال دستور اشپزی توضیح داده می شود.
هر چند بعضی الگوریتم ها خیلی پیچیده تر هستند.
الگوریتم ها معمولاً دارای مراحلی است که تکرار می شود تکرار و یا تا زمان پایان برنامه نیازمند decision هایی (مانند منطق بولی یا نابرابری است.
اگر الگوریتم مناسب و نا معیوب نباشد حتی با اجرای درست آن هم مسئله حل نمی شود.
برای مثال اجرای الگوریتم سالاد سیب زمینی در صورتی که سیب زمینی در کار نباشد حتی اگر تمام حرکات تهیه سالاد طوری انجام شود مثل اینکه سیب زمینی وجود دارد نا فرجام خواهد ماند.الگوریتم های مختلف ممکن است یک عمل را با دستورات مختلف در مدت زمان، جا، وبا تلاش کمتر یا بیشتری نسبت به بقیه انجام دهد.
برای مثال با داشتن دو دستور تهیه ی سالاد سیب زمینی، یکی ممکن است قبل از جوشاندن اول سیب زمینی را پوست بکند در حالی که دیگری این دو مرحله را برعکس انجام دهد، و هر دو این مراحل را برای تمام سیب زمینی ها تکرار می کنند تا وقتی که سالاد سیب زمینی آماده طبخ شود.(مثال ضعیف...
چه کسی سیب زمینی ها را جدا جدا می جوشاند؟
و معمولاً تهیه ی سالاد نیازی به پخت و پز ندارد...(
در بعضی کشورها، مثل امریکا، اگر تعبیه فیزیکی الگوریتم ها ممکن باشد ممکن است آن ها به شدت انحصاری شود (برای مثال، یک الگوریتم ضرب ممکن است در واحد محاسبه ی یک ریز پردازنده تعبیه شود (
________________________________________
الگوریتم های رسمی شده(formalized algorithms )
الگوریتم ها به خاطر روش پردازش اطلاعات توسط کامپیوتر اساسی و حیاتی هستند، چون یک برنامه کامپیوتری اساساً یک الگوریتم است که به کامپیوتر می گوید برای انجام یک عمل خاص مثل محاسبه حقوق کارمندان و یا چاپ ورقه گزارش دانش آموزان،چه مراحل خاصی را (با چه نظم خاصی) اجرا کند،.به این صورت، یک الگوریتم را می توان هر دنباله از دستوراتی که قابل اجرا توسط یک Turing complete باشد به حساب آورد.به طور نمونه ای هنگامی که الگوریتم کار پرازش اطلاعات را انجام می دهد، داده از طریق یک وسیله یا منبع ورودی گرفته، به یک وسیله خروجی یاsink نوشته و / یا برای استفاده در زمانی دیگر ذخیره می شود.
داده ذخیره شده به عنوان بخشی از حالت درونی(internal state) نهاد مجری الگوریتم تلقی می گردد.برای اعمال محاسباتی از این قبیل، الگوریتم باید به دقت تعریف شود :یعنی طوری مشخص شود که برای حالت مختلف محتمل معتبر باشد.
یعنی تمام مراحل شرطی باید به طور سیستماتیک بررسی شود ; حالت به حالت.ضابطه مربوط به هر حالت باید واضح (و محاسبه پذیر باشد(.چون الگوریتم ها لیست دقیقی از گام های دقیق است، نظم محاسبه تقریباً همیشه برای کار کرد الگوریتم اساسی می باشد.
همواره فرض می شود دستور ها روشن هستند، و گفته می شود از" بالا آغاز" و"تا پایین کشیده می شوند"، اندیشه ای که به طور رسمی تر توسط جریان کنترل توصیف می شود.تا اینجا ی بحث، رسمی سازی قواعد و قوانین برنامه نویسی امری(imperative programming) را به خود گرفت.
این عام ترین مفهوم است، و تلاش دارد با وسایل "مکانیکی" مجزا کاری را توصیف کند؛ عملیات تخصیص، تعیین مقدار یک متغیر، برای این مفهوم از الگوریتم رسمی شده یکتا می باشد .در زیر مثالی از این تخصیص آمده است.برای مفاهیم فرعی ) (alternative تشکیل دهنده یک الگوریتم برنامه نویسی تابعی و برنامه نویسی منطقی را ببینید.
ماشین حساب (آشنایی با Syntax Diagram(
ماشین حساب (آشنایی با Syntax Diagram( الگوریتم ماشین حسابی با تعریف زیر را بنویسید: انجام چهار عمل اصلی با اولویت محاسباتی عملگرها طبق آنچه در زیر مشخص شده است: کد: + - عملگر یگانی (Unary) * / + - عملگر دودویی (Binary) عبارات داخل پرانتز از اولویت بالاتری برخوردارند.
اعداد میتوانند صحیح یا اعشاری باشند.
پایان هر عبارت با علامت سوال (=) مشخص میشود.
خروج از ماشین حساب با ورود حرف ایکس (X) مشخص میشود.
مثال: کد: 2 * 3 + 4 * 5 = 26 2 * (3 + 4) * 5 = 70 2 * 3 + -4 * 5 = -14 8.1 / -2.5 = -3.24 X شرایط الگوریتم: برای گرفتن عبارت مورد محاسبه از کاربر٬ تنها یک تابع به نام GetChar وجود دارد که در هر زمان تنها یک کاراکتر از کاربر گرفته و آن را برمیگرداند.
به جز آخرین کاراکتر وارد شده توسط کاربر٬ الگوریتم نباید کاراکترهای قبلی وارد شده توسط کاربر را در متغیری ذخیره کند.
الگوریتم ارائه شده باید بر روی هر ماشین٬ سیستم عامل و زبان برنامهنویسی قابل پیادهسازی باشد.
برنامه نویسی تابعی برنامهنویسی تابعی یک دسته بندی برنامه نویسی است که با محاسبه به عنوان یک ارزیابی از تابعهای ریاضی رفتار میکند.
در مقایسه با برنامه نویسی آمرانه، برنامهنویسی تابعی روی ارزیابی عبارات تابعی نسبت به اجرای فرامین تاکید بیشتری دارد.
عبارات در این زبان با استفاده از توابع به منظور ترکیب مقادیر پایه ای شکل میگیرند.
توابع ریاضی استحکام زیادی از لحاظ تحلیل و تطابق دارند.
به عنوان مثال، اگر یک تابع idempotent شناخته شده باشد، یک فراخوانی تابع که خودش را به عنوان آرگومان میگیرد، و هیچ اثرات جانبی ندارد، ممکن است به صورت کارآمدی بدون فراخوانیهای چندگانه محاسبه شود.
یک تابع از این جهت، صفر یا تعداد بیشتری پارامتر ورودی، و یک مقدار بازگشتی دارد.
پارامترها ( یا آرگومانها، که گاهی به این نام خوانده میشوند) ورودیهای تابع هستند، و مقدار بازگشتی، خروجی تابع است.
تعریف تابع تشریح میکند که تابع چگونه باید برحسب توابع دیگر ارزیابی شود.
به عنوان مثال، تابع"" برحسب توابع توان و جمع تعریف شده است.
از بعضی دیدگاهها، زبان باید توابع اساسی را داشته باشد تا نیاز به تعریف بیشتر نباشد.
توابع میتوانند از راههای گوناگونی در یک زبان برنامهنویسی تابعی دستکاری شوند.
با توابع به عنوان مقدارهای کلاس اول رفتار میشود، که باید گفته شود توابع میتوانند پارامترها یا ورودیهای توابع دیگر بوده ونیز مقادیر بازگشتی یا خروجیهای یک تابع باشند.
این به توابعی مثل mapcar در LISP و map در Haskell اجازه میدهد که هم یک تابع و هم یک لیست را به عنوان ورودی بردارند و تابع ورودی را برای هر عنصر از لیست بکار برند.
توابع میتوانند نامگذاری شوند، مانند زبانهای دیگر، یا به صورت بینام ( گاهی در حین اجرای برنامه) با استفاده از انتزاع lambda تعریف شده و به عنوان مقدار در توابع دیگر استفاده شوند.
زبانهای تابعی همچنین به توابع، امکان "پرداخت" شدن را میدهد.
پرداخت یک تکنیک برای دوبارهنویسی یک تابع با پارامترهای چندگانه به عنوان ترکیبی از توابع یک پارامتر است.
یک تابع پرداخت شده می تواند برای یک زیر مجموعه از پارامترهایش به کار رود.
نتیجه تابعی است جایی که پارامترها در این زیر مجموعه حالا به عنوان ثابت ها، ثابت شده اند و مقادیر بقیه ی پارامترها هنوز نامشخص است.
این تابع جدید می تواند برای پارامترهای باقی مانده برای بدست آوردن مقدار تابع نهایی بکار رود.
به عنوان مثال، یک تابع میتواند پرداخت شود بنابراین مقدار بازگشتی (توجه داشته باشید که پارامتر y وجود ندارد) یک تابع بینام خواهد بود که معادل تابع است.
این تابع جدید فقط یک پارامتر دارد و معادل جمع 2 با یک عدد است.
دوباره تاکید میکنیم که چنین چیزی تنها به این دلیل ممکن است که با توابع به عنوان مقادیر کلاس اول رفتار میشود.
حساب Lambda میتواند اولین زبان برنامهنویسی تابعی در نظر گرفته شود، اگر چه برای اجرا روی یک کامپیوتر طراحی نشده است.
حساب Lambda یک مدل محاسبه است که به وسیلهی Alonzo Church در دههی 1930 طراحی شده است که یک راه خیلی رسمی برای توصیف ارزیابی تابع تامین می کند.
اولین زبان برنامهنویسی تابعی بر اساس کامپیوتر زبان پردازش اطلاعات (IPL) بود، که بوسیلهی Newell، Shaw، و Simon در شرکت RAND برای کامپیوتر JOHNNIAC در اواسط دههی 1950 گسترش یافت.
زبان برنامهنویسی تابعی پیشرفتهتر LISP بود که به وسیلهی جان مک کارتی در انستیتوی تکنولوژی ماساچوست برای کامپیوترهای علمی IBMسری 700/7000 در اواخر دههی1950 گسترش یافت.
در حالیکه LISP یک زبان برنامه نویسی تابعی کامل نبود، ولی بسیاری از خصیصه هایی را که الان در زبانهای برنامهنویسی تابعی مدرن یافت میشود را معرفی میکرد.
زبان Scheme تلاش بعدی برای ساده سازی و گسترش LISP بود.
در دههی 1970 زبان ML در دانشگاه ادینبرگ ایجاد شد، و دیوید ترنر زبان Muranda را در دانشگاه کنت گسترش داد.
زبان Haskell در اواخر دههی 1980 در یک تلاش برای جمع آوری نظرات در تحقیق برنامه نویسی تابعی ایجاد شد.
مقایسه با برنامهنویسی آمرانه برنامهنویسی تابعی میتواند با برنامه نویسی آمرانه مقایسه شود.
برنامهنویسی تابعی به نظر می رسد ساختارهای مختلفی را که برای یک زبان آمرانه ضروری است مثل C یا پاسکال از دست میدهد.
به عنوان مثال، در برنامهنویسی تابعی دقیق، هیچ تخصیص حافظهی صریح و هیچ تخصیص متغیر صریحی وجود ندارد.
اگرچه، این عملیات وقتی تابعی احضار میشود به صورت اتوماتیک اتفاق میافتد.
تخصیص حافظه برای ایجاد فضا برای پارامترها و مقدار بازگشتی انجام می شود و تخصیص برای کپی پارامترها به این فضای اختصاص یافتهی جدید و کپی مقدار بازگشتی به تابع فراخوانی شده اتفاق میافتد.
هر دو عملیات میتوانند فقط روی خروج و ورود تابع اجرا شوند، بنابراین اثرات جانبی ارزیابی تابع حذف میشود.
با رد کردن اثرات جانبی در توابع، زبان شفافیت ارجاعی پیدا میکند.
این سبب میشود که نتیجه ی یک تابع برای یک مجموعهی مشخص از پارامترها یکسان شود بدون اهمیت به اینکه کی و کجا ارزیابی شده است.
شفافیت ارجاعی به میزان زیادی وظیفه ی اثبات صحت برنامه و وظیفه ی شناسایی اتوماتیک محاسبات مستقل برای اجرای موازی را آسان میکند.
حلقه، دیگر ساختار برنامهنویسی آمرانه، در طول ساختار تابعی عمومی تر بازگشت انجام می شود.
توابع بازگشتی خودشان را احضار می کنند، و به یک عمل اجازهی اجرای مکرر را میدهند.
در حقیقت، میتوان ثابت کرد که حلقه معادل نوع خاصی از بازگشت است که بازگشت دنبالهای نامیده میشود.
بازگشت در برنامهنویسی تابعی می تواند شکلهای گوناگونی بگیرد و عموماً یک تکنیک قویتری نسبت به حلقه است.
به همین دلیل، تقریباً همهی زبانهای آمرانه نیز آن را پشتیبانی میکنند (بجز زبانهایی مثل FORTRAN 77 و COBOL).
زبانهای برنامهنویسی تابعی برنامههای تابعی "خالص" نیاز به هیچ متغیر و اثرات جانبی ندارد، و بنابراین به صورت اتوماتیک امنیت رشتهای ، قابلیت تغییر اتوماتیک ( تا زمانی که هر سیکل بازگشتی عاقبت بایستد) و بسیاری ماهیتهای خوب از این نوع دارند.
توابع تودرتو فقط نتایج شان را به تابع اصلی باز میگردانند.
تکمیل این زبانها معمولاً استفادهی کاملاً ماهرانهای از دستکاری stack را ممکن میسازد، همان طوری که معمولاً نیز استفاده میشود.
برنامهنویسی تابعی اغلب بستگی زیادی به بازگشت دارد.زبان برنامه نویسی Scheme حتی نیاز به انواع مشخص بازگشت بازگشت دنبالهای دارد که شناخته شود و به صورت اتوماتیک به وسیله کامپایلر بهینه شود.
درضمن، زبانهای برنامهنویسی تابعی احتمال دارد شفافیت مرجعی را اجرا کند، تصور آشنایی است که مساویها میتوانند با یکدیگر جایگزین شوند: اگر دو عبارت با مقدارهای مساوی تعریف شوند، یکی میتواند درهر عبارت بزرگتری، بدون تاثیر روی نتیجهی محاسبه جایگزین دیگری شود.
به عنوان مثال، در ما میتوانیم sqrt (2) را فاکتور بگیریم و بنویسیم بنابراین ارزیابی اضافی از تابع ریشهی دوم حذف میشود.
بدیهی است که چنین موردی همیشه در زبان آمرانه برقرار نیست.
یک مورد مناسب، تابع getchar ( ) زبان برنامه نویسی C است، که اکیداً تابعی است نه از آرگومانهایش که از محتوای جریان ورودی stdin و مقداری که قبلاً خوانده شده است.
به مثال روبرو توجه کنید: ما نمیتوانیم getchar ( ) را مانند sqrt (2) حذف کنیم، چون در C، " getchar ( )" باید دو مقدار متفاوت را در دو باری که فراخوانی میشود برگرداند.
اثرات جانبی مخفی، عموماً یک قانون از زبانهای برنامهنویسی قدیمی است، تا استثناء،.
هر بار یک رویه یک مقدار را میخواند یا یک مقدار را در یک متغیر global یا اشتراکی مینویسد، پتانسیل اثرات جانبی مخفی وجود دارد.
این نشر اطلاعات در طول مرزهای رویه به طریقی که صریحاً با تعاریف و فراخوانیهای تابع نشان داده نمیشود شدیداً پیچیدگی مخفی برنامههای نوشته شده در زبانهای غیر تابعی قراردادی را افزایش میدهد.
با حذف این شکافهای اطلاعاتی