
توابع Haskell می توانند توابع را به عنوان پارامترها و عملکردهای بازگشت به عنوان مقادیر برگشتی در نظر بگیرند. تابعی که هر یک از این موارد را انجام می دهد ، یک تابع مرتبه بالاتر نامیده می شود. عملکردهای مرتبه بالاتر فقط بخشی از تجربه هاسکل نیستند ، بلکه تقریباً تجربه هاسکل هستند. به نظر می رسد که اگر می خواهید محاسبات را با تعریف مواردی که به جای تعریف مراحل تغییر برخی از حالت ها و ممکن است حلقه های آنها را تعریف کنید ، تعریف کنید ، عملکردهای مرتبه بالاتر ضروری هستند. آنها یک روش واقعاً قدرتمند برای حل مشکلات و فکر کردن در مورد برنامه ها هستند.
توابع مجهز
هر عملکرد در هاکل رسما فقط یک پارامتر را می گیرد. بنابراین چگونه ممکن است که ما چندین کارکرد را تعریف و استفاده کنیم که تاکنون بیش از یک پارامتر طول می کشد؟خوب ، این یک ترفند هوشمندانه است! تمام کارکردهایی که تاکنون چندین پارامتر را پذیرفته اند ، توابع مورد استفاده قرار گرفته اند. معنی آن چیست؟شما آن را در یک مثال بهتر درک خواهید کرد. بیایید دوست خوب خود را ، عملکرد حداکثر بگیریم. به نظر می رسد که دو پارامتر طول می کشد و یکی را که بزرگتر است باز می گرداند. انجام MAX 4 5 ابتدا تابعی را ایجاد می کند که یک پارامتر را می گیرد و بسته به نوع آن ، 4 یا آن پارامتر را برمی گرداند. سپس ، 5 برای آن عملکرد اعمال می شود و آن عملکرد نتیجه دلخواه ما را تولید می کند. این به نظر می رسد مانند یک لقمه اما در واقع یک مفهوم واقعا جالب است. دو تماس زیر معادل است:
Putting a space between two things is simply function application . The space is sort of like an operator and it has the highest precedence. Let's examine the type of max . It's max :: (Ord a) => a > a > a . That can also be written as max :: (Ord a) => a > (a > a) . That could be read as: max takes an a and retus (that's the >) تابعی که A را می گیرد و A را برمی گرداند. به همین دلیل نوع بازگشت و پارامترهای توابع به سادگی با فلش از هم جدا می شوند.
بنابراین چگونه این برای ما مفید است؟به عبارت ساده تر ، اگر ما تابعی را با پارامترهای بسیار کمی فراخوانی کنیم ، یک عملکرد جزئی کاربردی را به دست می آوریم ، به معنای تابعی که پارامترهای زیادی را که از آن خارج شده است ، می گیرد. استفاده از برنامه های جزئی (توابع فراخوانی با پارامترهای بیش از حد ، در صورت تمایل) روشی مرتب برای ایجاد توابع در پرواز است تا بتوانیم آنها را به عملکرد دیگری منتقل کنیم یا با برخی از داده ها به آنها بذاریم.
به این عملکرد ساده و ساده نگاهی بیندازید:
What really happens when we do multThree 3 5 9 or ((multThree 3) 5) 9 ? First, 3 is applied to multThree , because they're separated by a space. That creates a function that takes one parameter and retus a function. So then 5 is applied to that, which creates a function that will take a parameter and multiply it by 15. 9 is applied to that function and the result is 135 or something. Remember that this function's type could also be written as multThree :: (Num a) => a > (a > (a > a)) . The thing before the > is the parameter that a function takes and the thing after it is what it retus. So our function takes an a and retus a function of type (Num a) => a > (a > a) . Similarly, this function takes an a and retus a function of type (Num a) => a >آ . و این عملکرد ، سرانجام ، فقط A را می گیرد و A را برمی گرداند. یه نگاهی به این بنداز:
با فراخوانی توابع با پارامترهای بسیار کمی ، به اصطلاح ، ما در حال ایجاد توابع جدید در پرواز هستیم. چه می شود اگر بخواهیم تابعی را ایجاد کنیم که یک عدد باشد و آن را با 100 مقایسه کند؟ما می توانیم چنین کاری انجام دهیم:
اگر آن را با 99 صدا کنیم ، GT را برمی گرداند. چیزهای سادهتوجه کنید که X در سمت راست در هر دو طرف معادله قرار دارد. حال بیایید در مورد چه چیزی 100 بازده را مقایسه کنیم. این تابعی را برمی گرداند که یک عدد را می گیرد و آن را با 100 مقایسه می کند. وای! آیا این عملکردی نیست که ما می خواستیم؟ما می توانیم این را بازنویسی کنیم:
The type declaration stays the same, because compare 100 retus a function.compare has a type of (Ord a) => a > (a > Ordering) and calling it with 100 retus a (Num a, Ord a) => a >مرتب سازی . محدودیت کلاس اضافی در آنجا حرکت می کند زیرا 100 نیز بخشی از num typeclass است.
مناطمینان حاصل کنید که واقعاً درک کرده اید که چگونه کارکردها و کاربردهای جزئی کار می کنند زیرا آنها واقعاً مهم هستند!
توابع infix همچنین می تواند تا حدی با استفاده از بخش ها اعمال شود. به بخش یک عملکرد infix ، آن را به سادگی با پرانتز احاطه کنید و فقط یک پارامتر را از یک طرف تأمین کنید. این تابعی را ایجاد می کند که یک پارامتر را به خود اختصاص می دهد و سپس آن را در طرفی که یک عملگر را از دست می دهد ، اعمال می کند. یک عملکرد توهین آمیز بی اهمیت:
تماس با ما ، DivideByten 200 معادل انجام 200/10 است ، همانطور که انجام می شود ( / 10) 200. تابعی که بررسی می کند که آیا یک شخصیت تهیه شده به آن یک حرف بزرگ است:
تنها مورد خاص در مورد بخش ها استفاده از -. از تعریف بخش ها ، (-4) منجر به عملکردی می شود که یک عدد را می گیرد و 4 را از آن جدا می کند. با این حال ، برای راحتی ، (-4) به معنای منهای چهار است. بنابراین اگر می خواهید تابعی را ایجاد کنید که 4 را از شماره ای که به عنوان یک پارامتر به دست می آورد ، تقسیم می کند ، تا حدی عملکرد تفریق مانند SA را اعمال کنید: (SUFTRACT 4).
چه اتفاقی می افتد اگر ما سعی کنیم به جای اینکه آن را به یک نام با یک اجازه دهیم یا آن را به عملکرد دیگری منتقل کنیم ، فقط Mul t-3 4 را در GHCI انجام دهیم؟
GHCI is telling us that the expression produced a function of type a >A اما نمی داند چگونه آن را روی صفحه چاپ کنید. توابع نمونه ای از نمایش Typeclass نیستند ، بنابراین ما نمی توانیم یک نمایش رشته ای از یک عملکرد را بدست آوریم. هنگامی که ما این کار را می کنیم ، 1 + 1 را در سریع GHCI ، ابتدا آن را به 2 محاسبه می کند و سپس با نمایش 2 تماس می گیرد تا یک نمایش متنی از آن شماره دریافت کند. و بازنمایی متنی 2 فقط رشته "2" است که سپس به صفحه ما چاپ می شود.
برخی از نظم های بالاتر به ترتیب است
توابع می توانند توابع را به عنوان پارامترها انجام دهند و همچنین توابع را برگردانند. برای نشان دادن این موضوع ، ما می خواهیم تابعی را بسازیم که یک عملکرد را انجام دهد و سپس آن را دو بار برای چیزی اعمال می کند!
First of all, notice the type declaration. Before, we didn't need parentheses because > is naturally right-associative. However, here, they're mandatory. They indicate that the first parameter is a function that takes something and retus that same thing. The second parameter is something of that type also and the retu value is also of the same type. We could read this type declaration in the curried way, but to save ourselves a headache, we'll just say that this function takes two parameters and retus one thing. The first parameter is a function (of type a > a ) and the second is that same a . The function can also be Int > Int or String >رشته یا هر چیز دیگری. اما پس از آن ، پارامتر دوم نیز باید از آن نوع باشد.
Note: From now on, we'll say that functions take several parameters despite each function actually taking only one parameter and retuing partially applied functions until we reach a function that retus a solid value. So for simplicity's sake, we'll say that a > a >A دو پارامتر را می گیرد ، حتی اگر می دانیم واقعاً زیر کاپوت چه می گذرد.
بدنه عملکرد بسیار ساده است. ما فقط از پارامتر F به عنوان یک تابع استفاده می کنیم ، X را با جدا کردن آنها با یک فضا و سپس استفاده مجدد از نتیجه در F استفاده می کنیم. به هر حال ، بازی با عملکرد:
جذابیت و سودمندی کاربرد جزئی مشهود است. اگر عملکرد ما به ما نیاز داشته باشد تا تابعی را که فقط یک پارامتر را می گیرد ، عبور دهیم ، ما فقط می توانیم یک تابع را تا حدی اعمال کنیم که فقط یک پارامتر طول بکشد و سپس آن را منتقل کنیم.
اکنون می خواهیم از برنامه نویسی مرتبه بالاتر برای اجرای یک عملکرد واقعاً مفید که در کتابخانه استاندارد است استفاده کنیم. به آن ZipWith گفته می شود. این یک تابع و دو لیست به عنوان پارامتر می گیرد و سپس با استفاده از عملکرد بین عناصر مربوطه به دو لیست می پیوندد. در اینجا نحوه اجرای آن آورده شده است:
Look at the type declaration. The first parameter is a function that takes two things and produces a third thing. They don't have to be of the same type, but they can. The second and third parameter are lists. The result is also a list. The first has to be a list of a 's, because the joining function takes a 's as its first argument. The second has to be a list of b 's, because the second parameter of the joining function is of type b . The result is a list of c 's. If the type declaration of a function says it accepts an a > b > c function as a parameter, it will also accept an a > a >یک تابع ، اما نه راه دیگر! به یاد داشته باشید که وقتی کارکردهایی را انجام می دهید ، به خصوص کارهای مرتبه بالاتر ، و از نوع آن مطمئن نیستید ، فقط می توانید از اعلام نوع خودداری کنید و سپس بررسی کنید که هاسکل با استفاده از: t.
عمل در عملکرد تقریباً شبیه به زیپ معمولی است. شرایط لبه یکسان است ، فقط یک استدلال اضافی ، عملکرد پیوستن وجود دارد ، اما این استدلال در شرایط لبه مهم نیست ، بنابراین ما فقط از _ برای آن استفاده می کنیم. و بدنه عملکرد در آخرین الگوی نیز شبیه به زیپ است ، فقط این کار را انجام نمی دهد (x ، y) ، بلکه f x y است. اگر به اندازه کافی کلی باشد ، می توان از یک تابع مرتبه بالاتر برای بسیاری از کارهای مختلف استفاده کرد. در اینجا نمایش کمی از همه چیزهای مختلف عملکرد zipwith ما می تواند انجام دهد:
همانطور که مشاهده می کنید ، از یک عملکرد مرتبه بالاتر می توان به روشهای بسیار متنوع استفاده کرد. برنامه نویسی ضروری معمولاً از چیزهایی مانند حلقه ها استفاده می کند ، در حالی که حلقه ها ، چیزی را روی یک متغیر قرار می دهند ، وضعیت آن را بررسی می کنند و غیره. برنامه نویسی کاربردی از توابع مرتبه بالاتری برای انتزاع الگوهای مشترک استفاده می کند ، مانند بررسی دو لیست به صورت جفت و انجام کاری با آن جفت ها یا گرفتن مجموعه ای از راه حل ها و از بین بردن موارد مورد نیاز شما.
ما عملکرد دیگری را که قبلاً در کتابخانه استاندارد به نام Flip وجود دارد ، پیاده سازی خواهیم کرد. Flip به سادگی یک عملکرد را می گیرد و تابعی را که مانند عملکرد اصلی ما است ، برمی گرداند ، فقط دو آرگومان اول می چرخند. ما می توانیم آن را مانند آن اجرا کنیم:
Reading the type declaration, we say that it takes a function that takes an a and a b and retus a function that takes a b and an a . But because functions are curried by default, the second pair of parentheses is really uecessary, because > is right associative by default. (a > b > c) > (b > a > c) is the same as (a > b > c) > (b > (a > c)) , which is the same as (a > b > c) > b > a >ج. ما نوشتیم که g x y = f y x. اگر این درست است ، پس f y x = g x y نیز باید نگه داشته شود ، درست است؟با توجه به این نکته ، می توانیم این عملکرد را به روشی ساده تر تعریف کنیم.
در اینجا ، ما از این واقعیت استفاده می کنیم که توابع مورد استفاده قرار می گیرند. هنگامی که ما بدون پارامترهای y و x flip 'f را صدا می کنیم ، یک F را برمی گرداند که آن دو پارامتر را می گیرد اما آنها را می خواند. حتی اگر توابع تلنگر معمولاً به کارکردهای دیگر منتقل می شوند ، می توانیم با فکر کردن در پیش رو و نوشتن نتیجه نهایی آنها در صورت استفاده کامل از آنها ، از انجام کار با سفارش بالاتر استفاده کنیم.
نقشه ها و فیلترها
MAP یک عملکرد و یک لیست را می گیرد و آن عملکرد را برای هر عنصر موجود در لیست اعمال می کند و یک لیست جدید تولید می کند. بیایید ببینیم امضای نوع آن چیست و چگونه تعریف شده است.
امضای نوع می گوید که عملکردی را می گیرد که A را می گیرد و A B را برمی گرداند ، لیستی از A 'S و لیستی از B را برمی گرداند. جالب است که فقط با نگاه کردن به امضای نوع عملکرد ، گاهی اوقات می توانید بگویید که چه کاری انجام می دهد. MAP یکی از این توابع واقعاً همه کاره با مرتبه بالاتر است که می تواند در میلیون ها روش مختلف مورد استفاده قرار گیرد. در اینجا در عمل است:
فیلتر تابعی است که یک محمول را می گیرد (محمول تابعی است که می گوید چیزی درست است یا خیر ، بنابراین در مورد ما ، تابعی که یک مقدار بولی را برمی گرداند) و یک لیست و سپس لیست عناصری را که محمول را برآورده می کنند ، برمی گرداندبشرامضای و اجرای نوع مانند این است:
چیزهای بسیار سادهاگر P X به True ارزیابی کند ، این عنصر در لیست جدید قرار می گیرد. اگر این کار را نکند ، باقی می ماند. برخی از نمونه های استفاده:
با استفاده از پیش بینی ها می توان با درک لیست نیز به همه اینها دست یافت. هیچ قانون مشخصی برای استفاده از نقشه و فیلتر در مقابل استفاده از درک لیست وجود ندارد ، فقط باید تصمیم بگیرید که بسته به کد و متن ، چه چیزی قابل خواندن است. معادل فیلتر استفاده از چندین گزاره در درک لیست ، فیلتر کردن چیزی چندین بار یا پیوستن به پیش بینی ها با عملکرد منطقی و & است.
عملکرد QuickSort ما را از فصل قبل به یاد دارید؟ما برای فیلتر کردن عناصر لیست کوچکتر از (یا مساوی) و بزرگتر از محوری ، از درک لیست استفاده کردیم. ما می توانیم با استفاده از فیلتر ، به همان عملکرد به روش قابل خواندن دست یابیم:

نقشه برداری و فیلتر کردن نان و کره جعبه ابزار برنامه نویس هر برنامه نویس است. اوهفرقی نمی کند که این کار را با توابع نقشه و فیلتر انجام دهید یا درک مطلب را لیست کنید. به یاد بیاورید که چگونه مشکل پیدا کردن مثلث های مناسب را با یک محیط خاص حل کردیم. با برنامه نویسی ضروری ، ما آن را با لانه سازی سه حلقه حل می کردیم و سپس آزمایش می کردیم که آیا ترکیب فعلی یک مثلث مناسب را برآورده می کند و اگر محیط مناسب داشته باشد. اگر اینگونه باشد ، ما آن را به صفحه یا چیزی چاپ می کردیم. در برنامه نویسی عملکردی ، این الگوی با نقشه برداری و فیلتر حاصل می شود. شما تابعی را ایجاد می کنید که یک مقدار را می گیرد و نتیجه ای را به دست می آورد. ما آن را روی لیستی از مقادیر نقشه می کشیم و سپس لیست حاصل را برای نتایج حاصل از جستجوی ما فیلتر می کنیم. به لطف تنبلی هاسکل ، حتی اگر چندین بار چیزی را روی لیست نقشه برداری کنید و چندین بار آن را فیلتر کنید ، فقط یک بار از لیست عبور می کند.
بیایید بیشترین تعداد زیر 100000 را که 3829 قابل تقسیم است پیدا کنیم. برای انجام این کار ، ما فقط مجموعه ای از امکانات را که در آن می دانیم راه حل نهفته است ، فیلتر خواهیم کرد.
ما ابتدا لیستی از همه اعداد را پایین تر از 100000 ، نزولی تهیه می کنیم. سپس ما آن را توسط محمول خود فیلتر می کنیم و از آنجا که اعداد به صورت نزولی طبقه بندی می شوند ، بیشترین تعداد که محمول ما را برآورده می کند اولین عنصر لیست فیلتر شده است. ما حتی نیازی به استفاده از لیست محدود برای مجموعه شروع خود نداشتیم. این دوباره تنبلی در عمل است. از آنجا که ما فقط با استفاده از سر لیست فیلتر شده به پایان می رسیم ، مهم نیست که لیست فیلتر شده محدود باشد یا نامتناهی باشد. ارزیابی هنگامی متوقف می شود که اولین راه حل کافی پیدا شود.
در مرحله بعد ، ما قصد داریم جمع همه مربع های عجیب و غریب را که از 10،000 کوچکتر هستند ، پیدا کنیم. اما اول ، زیرا ما از آن در راه حل خود استفاده خواهیم کرد ، می خواهیم عملکرد عاقلانه را معرفی کنیم. یک محمول و یک لیست طول می کشد و سپس از ابتدای لیست می رود و عناصر آن را برمی گرداند در حالی که محمول صحیح است. هنگامی که یک عنصر یافت می شود که محمول برای آن نگه نمی دارد ، متوقف می شود. اگر می خواستیم اولین کلمه رشته "فیل ها را می دانند که مهمانی را می دانند" بگیریم ، می توانستیم "فیل ها را می دانند که چگونه مهمانی کنند" را انجام دهیم و این "فیل ها" را بازگرداند. باشه. مجموع مربع های عجیب و غریب که از 10،000 کوچکتر هستند. ابتدا با نقشه برداری از عملکرد (^2) به لیست بی نهایت [1 ..] شروع می کنیم. سپس آنها را فیلتر می کنیم تا فقط موارد عجیب و غریب را بدست آوریم. و پس از آن ، ما عناصری را از آن لیست می گیریم در حالی که آنها از 10،000 کوچکتر هستند. سرانجام ، جمع آن لیست را دریافت خواهیم کرد. ما حتی لازم نیست که عملکردی را برای آن تعریف کنیم ، می توانیم آن را در یک خط در GHCI انجام دهیم:
عالی! ما با برخی از داده های اولیه (لیست نامحدود از همه اعداد طبیعی) شروع می کنیم و سپس بر روی آن نقشه می کنیم ، آن را فیلتر می کنیم و آن را برش می دهیم تا متناسب با نیازهای ما باشد و سپس فقط آن را خلاصه می کنیم. ما همچنین می توانستیم این کار را با استفاده از لیست درک مطلب بنویسیم:
این موضوع طعم و مزه ای است که کدام یک را زیباتر می دانید. باز هم ، خاصیت تنبلی هاکل همان چیزی است که این امر را ممکن می سازد. ما می توانیم یک لیست نامحدود را نقشه برداری کنیم و فیلتر کنیم ، زیرا در واقع آن را نقشه و فیلتر نمی کند ، این اقدامات را به تأخیر می اندازد. فقط هنگامی که ما هاکل را مجبور می کنیم تا به ما نشان دهد که مبلغ عملکرد جمع را به آنچه که به آن اعداد احتیاج دارد ، می گوید. تصفیه و نقشه برداری را مجبور می کند تا فیلتر و نقشه برداری رخ دهد ، اما فقط تا زمانی که یک عدد بیشتر از یا مساوی با 10،000 روبرو نشود.
برای مشکل بعدی ما ، با توالی های Collatz سر و کار خواهیم داشت. ما یک شماره طبیعی می گیریم. اگر این تعداد یکنواخت باشد ، ما آن را به دو تقسیم می کنیم. اگر عجیب است ، ما آن را با 3 ضرب می کنیم و سپس 1 را به آن اضافه می کنیم. ما شماره حاصل را می گیریم و همان چیزها را برای آن اعمال می کنیم ، که شماره جدیدی را تولید می کند و غیره. در اصل ، زنجیره ای از اعداد را می گیریم. تصور می شود که برای همه اعداد شروع ، زنجیرها در شماره 1 به پایان می رسند. بنابراین اگر شماره 13 را بگیریم ، این دنباله را می گیریم: 13 ، 40 ، 20 ، 10 ، 5 ، 16 ، 8 ، 4 ، 2 ، 1بشر13*3 + 1 برابر با 40. 40 تقسیم شده توسط 2 20 است ، و غیره. می بینیم که این زنجیره 10 اصطلاح دارد.
اکنون آنچه می خواهیم بدانیم این است: برای همه شماره های شروع بین 1 تا 100 ، چند زنجیره طول بیشتر از 15 دارند؟اول از همه ، ما تابعی را می نویسیم که یک زنجیره تولید می کند:
از آنجا که زنجیرها در 1 به پایان می رسند ، این مورد لبه است. این یک عملکرد بازگشتی بسیار استاندارد است.
بلهبه نظر می رسد به درستی کار می کند. و اکنون ، عملکردی که پاسخ سوال ما را به ما می گوید:
ما عملکرد زنجیره ای را به [1.. 100] ترسیم می کنیم تا لیستی از زنجیرها را بدست آوریم ، که خودشان به عنوان لیست ها نشان داده شده اند. سپس ، ما آنها را با یک محمول فیلتر می کنیم که فقط بررسی می کند که آیا طول یک لیست طولانی تر از 15 است. پس از انجام فیلتر ، می بینیم که چه تعداد زنجیره ای در لیست حاصل باقی مانده است.
توجه: این عملکرد دارای یک نوع numlongchains :: int است زیرا طول به دلایل تاریخی به جای یک شماره A ، یک int را برمی گرداند. اگر می خواستیم یک شماره کلی تر A را برگردانیم ، می توانستیم از طول نتیجه استفاده کنیم.
Using map , we can also do stuff like map (*) [0..] , if not for any other reason than to illustrate how currying works and how (partially applied) functions are real values that you can pass around to other functions or put into lists (you just can't tu them to strings). So far, we've only mapped functions that take one parameter over lists, like map (*2) [0..] to get a list of type (Num a) => [a] , but we can also do map (*) [0..] without a problem. What happens here is that the number in the list is applied to the function * , which has a type of (Num a) => a > a > a . Applying only one parameter to a function that takes two parameters retus a function that takes one parameter. If we map * over the list [0..] , we get back a list of functions that only take one parameter, so (Num a) => [a >آ] . نقشه (*) [0 ..] لیستی مانند نمونه ای را که می خواهیم با نوشتن [(0*) ، (1*) ، (2*) ، (3*) ، (4*) ، (5*) تهیه می کند.) ...
گرفتن عنصر با فهرست 4 از لیست ما تابعی را که معادل (4*) است ، برمی گرداند. و بعد ، ما فقط 5 را برای آن عملکرد اعمال می کنیم. بنابراین این مانند نوشتن (4 *) 5 یا فقط 4 * 5 است.
گوسفند

Lambdas are basically anonymous functions that are used because we need some functions only once. Normally, we make a lambda with the sole purpose of passing it to a higher-order function. To make a lambda, we write a (because it kind of looks like the greek letter lambda if you squint hard enough) and then we write the parameters, separated by spaces. After that comes a >و سپس بدن عملکرد. ما معمولاً آنها را توسط پرانتز احاطه می کنیم ، زیرا در غیر این صورت آنها تمام راه را به سمت راست می کشند.
اگر حدود 5 اینچ به بالا نگاه کنید ، خواهید دید که ما از یک اتصال در عملکرد Numlongchains خود استفاده کرده ایم تا عملکرد Islong را برای تنها هدف عبور از آن برای فیلتر کردن انجام دهیم. خوب ، به جای انجام این کار ، می توانیم از لامبدا استفاده کنیم:
Lambdas are expressions, that's why we can just pass them like that. The expression (xs > length xs>15) تابعی را که به ما می گوید آیا طول لیست منتقل شده به آن بیشتر از 15 است ، برمی گرداند.

People who are not well acquainted with how currying and partial application works often use lambdas where they don't need to. For instance, the expressions map (+3) [1,6,3,2] and map (x > x + 3) [1,6,3,2] are equivalent since both (+3) and (x >x + 3) توابعی هستند که یک عدد را می گیرند و 3 را به آن اضافه می کنند. نیازی به گفتن نیست ، ساختن یک لامبدا در این حالت احمقانه است زیرا استفاده از برنامه های جزئی بسیار خواندنی است.
مانند توابع عادی ، لامبدا می تواند هر تعداد پارامترها را به دست آورد:
و مانند عملکردهای عادی ، می توانید در لامبدا مطابقت داشته باشید. تنها تفاوت این است که شما نمی توانید چندین الگوی را برای یک پارامتر تعریف کنید ، مانند ساخت یک الگوی [] و A (x: xs) برای همان پارامتر و سپس داشتن مقادیر از بین می رود. اگر یک الگوی تطبیق در یک لامبدا شکست خورد ، یک خطای زمان اجرا رخ می دهد ، بنابراین هنگام تطبیق الگوی در لامبدا مراقب باشید!
لامبدا معمولاً توسط پرانتز احاطه شده است ، مگر اینکه منظور ما این باشد که آنها تمام راه را به سمت راست گسترش دهند. در اینجا چیز جالبی وجود دارد: با توجه به نحوه انجام توابع به طور پیش فرض ، این دو معادل هستند:
If we define a function like this, it's obvious why the type declaration is what it is. There are three >در هر دو نوع اعلامیه و معادله. اما مطمئناً ، اولین راه برای نوشتن توابع بسیار خواندنی است ، مورد دوم تقریباً یک حیله برای نشان دادن کاری است.
با این حال ، مواقعی وجود دارد که استفاده از این نماد خنک است. من فکر می کنم که عملکرد FLIP در صورت تعریف چنین قابل خواندن است:
حتی اگر این همان نوشتن Flip 'f X y = f y x باشد ، ما بدیهی می کنیم که بیشتر اوقات برای تولید یک عملکرد جدید استفاده می شود. متداول ترین مورد استفاده با Flip ، آن را فقط با پارامتر عملکرد فراخوانی کرده و سپس عملکرد حاصل را به نقشه یا فیلتر منتقل می کنید. بنابراین وقتی می خواهید صریحاً این کار را انجام دهید ، از این روش استفاده کنید که عملکرد شما عمدتاً به منظور استفاده جزئی انجام شود و به عنوان یک پارامتر به یک تابع منتقل شود.
فقط تاشو و اسبها

هنگامی که ما با بازگشت به آنجا سر و کار داشتیم ، در بسیاری از کارکردهای بازگشتی که در لیست ها فعالیت می کردند ، متوجه موضوعی شدیم. معمولاً ، ما یک مورد لبه برای لیست خالی خواهیم داشت. ما الگوی X: XS را معرفی می کنیم و سپس می توانیم برخی از اقدامات را انجام دهیم که شامل یک عنصر واحد و بقیه لیست است. به نظر می رسد این یک الگوی بسیار رایج است ، بنابراین یک زن و شوهر از عملکردهای بسیار مفید برای محاصره کردن آن معرفی شدند. این توابع برابر نامیده می شود. آنها مانند عملکرد نقشه هستند ، فقط آنها لیست را به مقداری مقدار واحد کاهش می دهند.
یک برابر یک عملکرد باینری ، یک مقدار شروع (من دوست دارم آن را به عنوان باتری بنامم) و یک لیست برای جمع کردن. عملکرد باینری به خودی خود دو پارامتر می گیرد. عملکرد باینری با باتری و عنصر اول (یا آخرین) خوانده می شود و یک باتری جدید تولید می کند. سپس ، عملکرد باینری دوباره با باتری جدید و عنصر اول (یا آخرین) جدید و غیره نامیده می شود. هنگامی که ما در کل لیست قدم زدیم ، فقط باتری باقی می ماند ، این همان چیزی است که ما لیست را به آن کاهش داده ایم.
ابتدا بیایید نگاهی به عملکرد Foldl بیندازیم ، همچنین به عنوان سمت چپ نیز نامیده می شود. لیست را از سمت چپ جمع می کند. عملکرد باینری بین مقدار شروع و سر لیست اعمال می شود. این یک مقدار باتری جدید تولید می کند و عملکرد باینری با آن مقدار و عنصر بعدی و غیره خوانده می شود.
بیایید دوباره جمع کنیم ، فقط این بار ، ما به جای بازگشت صریح ، از یک برابر استفاده خواهیم کرد.
تست ، یک دو سه:
Let's take an in-depth look into how this fold happens. acc x >ACC + X عملکرد باینری است. 0 مقدار شروع و XS لیستی است که باید جمع شود. اکنون ابتدا ، 0 به عنوان پارامتر ACC به عملکرد باینری استفاده می شود و 3 به عنوان پارامتر X (یا عنصر فعلی) استفاده می شود. 0 + 3 یک 3 تولید می کند و به ارزش جمع کننده جدید تبدیل می شود. در مرحله بعد ، 3 به عنوان مقدار باتری و 5 به عنوان عنصر فعلی و 8 به مقدار باتری جدید تبدیل می شود. در حال حرکت به جلو ، 8 مقدار باتری است ، 2 عنصر فعلی ، مقدار باتری جدید 10 است. سرانجام ، این 10 به عنوان مقدار باتری و 1 به عنوان عنصر فعلی استفاده می شود و 11 را تولید می کند. تبریک می گویم ، شما یک برابر انجام داده اید!
این نمودار حرفه ای در سمت چپ نشان می دهد که چگونه یک برابر اتفاق می افتد ، قدم به قدم (روز به روز!). عدد قهوه ای سبز مقدار باتری است. می توانید ببینید که چگونه لیست از سمت چپ توسط باتری از سمت چپ استفاده می شود. om nom nom! اگر در نظر بگیریم که توابع مورد استفاده قرار می گیرند ، می توانیم این اجرای را به طور دقیق تر بنویسیم ، مانند این:
The lambda function (acc x >acc + x) همان ( +) است. ما می توانیم XS را به عنوان پارامتر حذف کنیم زیرا فراخوانی Foldl (+) 0 عملکردی را که لیست می کند ، باز می گرداند. به طور کلی ، اگر عملکردی مانند foo a = bar b a دارید ، می توانید آن را به عنوان foo = bar b بازنویسی کنید ، به دلیل کاری.
به هر حال ، بیایید قبل از حرکت به سمت راست ، عملکرد دیگری را با برابر سمت چپ پیاده سازی کنیم. من مطمئن هستم که همه شما می دانید که ELEM بررسی می کند که آیا یک مقدار بخشی از یک لیست است ، بنابراین من دیگر به آن نمی روم (Whoops ، فقط این کار را کردم!). بیایید آن را با یک برابر سمت چپ پیاده سازی کنیم.
بسیار خوب، اینجا چی داریم؟مقدار شروع و باتری در اینجا یک مقدار بولی است. نوع مقدار باتری و نتیجه نهایی همیشه هنگام برخورد با چین ها یکسان است. به یاد داشته باشید که اگر هرگز نمی دانید از چه چیزی به عنوان یک مقدار شروع استفاده کنید ، ایده ای به شما می دهد. ما با دروغ شروع می کنیم. منطقی است که از FALSE به عنوان مقدار شروع استفاده کنیم. ما تصور می کنیم آنجا نیست. همچنین ، اگر در یک لیست خالی به همبند ، نتیجه فقط مقدار شروع خواهد بود. سپس بررسی می کنیم عنصر فعلی عنصری است که به دنبال آن هستیم. اگر اینطور باشد ، ما باتری را درست تنظیم می کنیم. اگر اینگونه نباشد ، ما فقط باتری را بدون تغییر می گذاریم. اگر قبلاً نادرست بود ، اینگونه باقی می ماند زیرا این عنصر فعلی چنین نیست. اگر این درست بود ، ما آن را در آن ترک می کنیم.
The right fold, foldr works in a similar way to the left fold, only the accumulator eats up the values from the right. Also, the left fold's binary function has the accumulator as the first parameter and the current value as the second one (so acc x > . ), the right fold's binary function has the current value as the first parameter and the accumulator as the second one (so x acc >بشر). این یک نوع منطقی است که چین راست دارای باتری در سمت راست است ، زیرا از سمت راست می چرخد.
مقدار باتری (و از این رو نتیجه) یک برابر می تواند از هر نوع باشد. این می تواند یک عدد ، یک بولی یا حتی یک لیست جدید باشد. ما عملکرد MAP را با برابر مناسب پیاده سازی خواهیم کرد. باتری یک لیست خواهد بود ، ما عنصر لیست نقشه برداری را بر اساس عنصر جمع می کنیم. از آن ، بدیهی است که عنصر شروع یک لیست خالی خواهد بود.
اگر در حال نقشه برداری (+3) به [1،2،3] هستیم ، از سمت راست به لیست نزدیک می شویم. ما آخرین عنصر را که 3 است ، می گیریم و عملکرد را روی آن اعمال می کنیم ، که در نهایت 6 است. سپس ، ما آن را به باتری ، که [] بود ، آماده می کنیم. 6: [] [6] است و این اکنون باتری است. ما (+3) را به 2 اعمال می کنیم ، این 5 است و ما آن را به باتری می دهیم ، بنابراین باتری اکنون [5،6] است. ما (+3) را به 1 اعمال می کنیم و آن را به باتری می پردازیم و بنابراین مقدار نهایی [4،5،6] است.
Of course, we could have implemented this function with a left fold too. It would be map' f xs = foldl (acc x >ACC ++ [f x]) [] xs ، اما نکته این است که عملکرد ++ بسیار گرانتر از است: ، بنابراین ما معمولاً هنگام تهیه لیست های جدید از لیست ، از چین های مناسب استفاده می کنیم.

اگر لیستی را معکوس کنید ، می توانید درست مانند آن که می توانستید یک چاشنی چپ را انجام دهید و برعکس. بعضی اوقات حتی مجبور نیستید این کار را انجام دهید. عملکرد جمع تقریباً با یک برابر چپ و راست قابل اجرا است. یک تفاوت بزرگ این است که چین های راست روی لیست های بی نهایت کار می کنند ، در حالی که موارد چپ این کار را نمی کنند! به بیان ساده ، اگر در مقطعی یک لیست نامحدود بگیرید و آن را از سمت راست جمع کنید ، در نهایت به ابتدای لیست خواهید رسید. با این حال ، اگر یک لیست نامحدود را در یک نقطه بگیرید و سعی می کنید آن را از سمت چپ جمع کنید ، هرگز به پایان نمی رسد!
Folds می تواند برای پیاده سازی هر عملکردی که در آن یک لیست را یک بار ، عنصر بر اساس عنصر طی می کنید ، استفاده شود و سپس چیزی را بر اساس آن برگردانید. هر زمان که می خواهید لیستی را برای بازگشت به چیزی طی کنید ، احتمالاً می خواهید یک برابر کنید. به همین دلیل تاشو به همراه نقشه ها و فیلترها یکی از مفیدترین انواع توابع در برنامه نویسی عملکردی است.
توابع Foldl1 و Foldr1 بسیار شبیه به Foldl و FoldR کار می کنند ، فقط شما نیازی به ارائه مقدار شروع صریح ندارید. آنها فرض می کنند که اولین (یا آخرین) عنصر لیست مقدار شروع است و سپس تاشو را با عنصر کنار آن شروع می کند. با توجه به این نکته ، عملکرد جمع می تواند مانند SO اجرا شود: sum = foldl1 (+). از آنجا که آنها به لیست هایی که حداقل یک عنصر را جمع می کنند ، بستگی دارند ، در صورت فراخوانی با لیست های خالی ، خطاهای زمان اجرا را ایجاد می کنند. Foldl و Foldr ، از طرف دیگر ، با لیست های خالی خوب کار می کنند. هنگام تهیه تاشو ، در مورد نحوه عملکرد آن در یک لیست خالی فکر کنید. اگر عملکرد هنگام لیست خالی معنی نداشته باشد ، احتمالاً می توانید برای اجرای آن از FoldL1 یا FoldR1 استفاده کنید.
فقط برای اینکه به شما نشان دهیم که چین های قدرتمند چقدر قدرتمند هستند ، ما می خواهیم مجموعه ای از توابع استاندارد کتابخانه را با استفاده از چین ها پیاده سازی کنیم:
head is better implemented by patte matching, but this just goes to show, you can still achieve it by using folds. Our reverse' definition is pretty clever, I think. We take a starting value of an empty list and then approach our list from the left and just prepend to our accumulator. In the end, we build up a reversed list. acc x >X: ACC نوع ظاهری مانند: تابع ، فقط پارامترها می چرخند. به همین دلیل می توانستیم معکوس خود را به عنوان Foldl (Flip (:)) [] بنویسیم.
راه دیگر برای تصویر کردن چین های راست و چپ مانند این است: بگویید ما یک برابر راست داریم و عملکرد باینری F و مقدار شروع Z است. اگر حق داریم در لیست [3،4،5،6] قرار بگیریم ، در اصل این کار را انجام می دهیم: F 3 (F 4 (F 5 (F 6 Z))). F با آخرین عنصر موجود در لیست و باتری خوانده می شود ، این مقدار به عنوان باتری به مقدار بعدی برای آخرین مقدار و غیره داده می شود. اگر ما F را به + و مقدار باتری شروع می کنیم تا 0 باشد ، یعنی 3 + (4 + (5 + (6 + 0))). یا اگر به عنوان یک تابع پیشوند می نویسیم ، این (+) 3 ((+) 4 ((+) 5 ((+) 6 0))) است. به طور مشابه ، انجام تاشو سمت چپ بر روی آن لیست با G به عنوان عملکرد باینری و z به عنوان باتری معادل G (G (G (G Z 3) 4) 5) 6 است. اگر از تلنگر استفاده کنیم (:) به عنوان عملکرد باینری و [] به عنوان باتری (بنابراین ما لیست را معکوس می کنیم) ، پس این معادل تلنگر است (:) (Flip (:) (Flip (:) (Flip (: :)) [] 3) 4) 5) 6. و مطمئناً ، اگر آن عبارت را ارزیابی کنید ، [6،5،4،3] دریافت می کنید.
Scanl و ScanR مانند Foldl و FoldR هستند ، فقط آنها تمام حالت های باتری متوسط را در قالب یک لیست گزارش می دهند. همچنین ScanL1 و ScanR1 وجود دارد که شبیه به Foldl1 و FoldR1 هستند.
هنگام استفاده از اسکنل ، نتیجه نهایی در آخرین عنصر لیست حاصل خواهد بود در حالی که یک SCANR نتیجه را در سر قرار می دهد.
از اسکن ها برای نظارت بر پیشرفت عملکردی که می تواند به عنوان برابر اجرا شود استفاده می شود. بیایید این سؤال را به ما پاسخ دهیم: چند عنصر برای جمع شدن ریشه های همه اعداد طبیعی بیش از 1000 است؟برای به دست آوردن مربع همه اعداد طبیعی ، ما فقط نقشه SQRT را انجام می دهیم [1 ..]. اکنون ، برای به دست آوردن مبلغ ، ما می توانیم یک برابر را انجام دهیم ، اما از آنجا که ما علاقه مند به پیشرفت جمع هستیم ، می خواهیم اسکن کنیم. هنگامی که اسکن را انجام دادیم ، فقط می بینیم که تعداد مبلغ زیر 1000 است. اولین مبلغ در لیست اسکن 1 ، به طور عادی خواهد بود. دوم 1 به علاوه ریشه مربع 2 خواهد بود. سوم به علاوه ریشه مربع 3 خواهد بود. اگر تعداد X در زیر 1000 وجود داشته باشد ، برای این مبلغ بیش از 1000 عنصر x+1 طول می کشد.
ما در اینجا به جای فیلتر استفاده می کنیم زیرا فیلتر در لیست های نامحدود کار نمی کند. حتی اگر می دانیم که این لیست صعود است ، فیلتر نمی کند ، بنابراین ما برای برش لیست اسکن در اولین وقوع مبلغ بیشتر از 1000 استفاده می کنیم.
برنامه عملکرد با $
خوب ، در مرحله بعد ، ما به عملکرد $ ، که به آن برنامه عملکرد نیز گفته می شود ، می پردازیم. اول از همه ، بیایید بررسی کنیم که چگونه تعریف شده است:
چه هک؟این اپراتور بی فایده چیست؟این فقط برنامه کاربردی است! خوب ، تقریباً ، اما نه کاملاً! در حالی که کاربرد عملکرد عادی (قرار دادن فضایی بین دو چیز) دارای برتری بسیار بالایی است ، عملکرد $ کمترین سابقه را دارد. کاربرد عملکرد با یک فضا در سمت چپ است (بنابراین f a b c همان است ((f a) b) c)) ، برنامه کاربردی با $ مناسب است.
این خیلی خوب است ، اما چگونه این به ما کمک می کند؟بیشتر اوقات ، این یک عملکرد راحتی است به گونه ای که لازم نیست پرانتز زیادی بنویسیم. مبلغ عبارت را در نظر بگیرید (نقشه SQRT [1.. 130]). از آنجا که $ چنین سابقه کمتری دارد ، می توانیم این عبارت را به عنوان مبلغ $ نقشه sqrt [1.. 130] بازنویسی کنیم و خودمان را صرفه جویی در کلیدهای گرانبها! هنگامی که یک $ روبرو می شود ، عبارت در سمت راست آن به عنوان پارامتر عملکرد در سمت چپ آن اعمال می شود. در مورد SQRT 3 + 4 + 9 چطور؟این به هم می رسد 9 ، 4 و ریشه مربع 3. اگر می خواهیم ریشه مربع 3 + 4 + 9 را بدست آوریم ، باید SQRT (3 + 4 + 9) را بنویسیم یا اگر از $ استفاده کنیم می توانیم آن را بنویسیمبه عنوان SQRT 3 + 4 + 9 به دلیل $ کمترین تقدم هر اپراتور را دارد. به همین دلیل می توانید یک $ را به نوعی معادل نوشتن یک پرانتز باز و سپس نوشتن یک بسته در سمت راست بیان تصور کنید.
How about sum (filter (> 10) (map (*2) [2..10])) ? Well, because $ is right-associative, f (g (z x)) is equal to f $ g $ z x . And so, we can rewrite sum (filter (> 10) (map (*2) [2..10])) as sum $ filter (>10) $ نقشه (*2) [2.. 10].
اما جدای از خلاص شدن از شر پرانتز، $ به این معنی است که برنامه تابع را می توان دقیقاً مانند یک تابع دیگر در نظر گرفت. به این ترتیب، به عنوان مثال، می توانیم برنامه کاربردی تابع را روی فهرستی از توابع ترسیم کنیم.
ترکیب تابع

در ریاضیات، ترکیب تابع به این صورت تعریف می شود: به این معنی که با ترکیب دو تابع، تابع جدیدی تولید می شود که وقتی با یک پارامتر، مثلاً x فراخوانی می شود، معادل آن است که g را با پارامتر x و سپس f را با آن نتیجه فراخوانی کنیم.
در Haskell، ترکیب تابع تقریباً یکسان است. ما ترکیب تابع را با . تابعی که به این صورت تعریف می شود:

به اعلان نوع توجه کنید. f باید مقداری را به عنوان پارامتر خود انتخاب کند که دارای همان نوع مقدار بازگشتی g باشد. بنابراین تابع به دست آمده پارامتری از همان نوع را می گیرد که g می گیرد و مقداری از همان نوع را که f برمی گرداند برمی گرداند. بیان نفی .(* 3) تابعی را برمی گرداند که عددی را می گیرد، آن را در 3 ضرب می کند و سپس آن را نفی می کند.
یکی از کاربردهای ترکیب تابع، ساخت توابع در حال پرواز برای انتقال به توابع دیگر است. مطمئناً، می توان از لامبدا برای آن استفاده کرد، اما بسیاری از اوقات، ترکیب عملکرد واضح تر و مختصرتر است. فرض کنید ما لیستی از اعداد داریم و می خواهیم همه آنها را به اعداد منفی تبدیل کنیم. یک راه برای انجام این کار این است که قدر مطلق هر عدد را بدست آوریم و سپس آن را نفی کنیم، مانند:
به لامبدا و نحوه ظاهر آن به ترکیب تابع نتیجه توجه کنید. با استفاده از ترکیب تابع، می توانیم آن را به صورت زیر بازنویسی کنیم:
شگفت آور! ترکیب توابع راست-تداعی است، بنابراین ما می توانیم بسیاری از توابع را در یک زمان بسازیم. عبارت f (g (z x)) معادل (f . g . z) x است. با در نظر گرفتن این موضوع، ما می توانیم برگردیم
اما در مورد توابعی که چندین پارامتر دارند؟خوب ، اگر می خواهیم از آنها در ترکیب عملکرد استفاده کنیم ، معمولاً باید آنها را تا حدی به همان اندازه اعمال کنیم که هر عملکرد فقط یک پارامتر را می گیرد. مبلغ (تکرار 5 (حداکثر 6. 7 8. 9)) را می توان به عنوان (مبلغ تکرار 5. حداکثر 6. 7) 8. 9 یا به عنوان جمع بازنویسی کرد. تکرار 5. حداکثر 6. 7 $ 8. 9. آنچه در اینجا اتفاق می افتد این است: تابعی که آنچه را که حداکثر 6. 7 در آن استفاده می کند و تکرار 5 را برای آن ایجاد می کند ، ایجاد می کند. سپس ، تابعی که نتیجه آن را می گیرد و مبلغی از آن را انجام می دهد. سرانجام ، این عملکرد با 8. 9 خوانده می شود. اما به طور معمول ، شما فقط آن را خوانده اید: 8. 9 را به حداکثر 6. 7 اعمال کنید ، سپس 5 را در آن تکرار کنید و سپس مبلغ آن را اعمال کنید. اگر می خواهید با استفاده از ترکیب عملکرد ، یک عبارت با پرانتز زیادی را بازنویسی کنید ، می توانید با قرار دادن آخرین پارامتر عملکرد درونی پس از یک $ و سپس فقط آهنگسازی تمام تماس های عملکرد دیگر ، نوشتن آنها بدون آخرین پارامتر و قرار دادن آنها را شروع کنید. نقاط بین آنها. اگر 100 (محصول (*3)) را تکرار کرده اید (ZipWith Max [1،2،3،4،5] [4،5،6،7،8]))) ، می توانید آن را به صورت تکرار 100 بنویسید. تولید - محصول . نقشه (*3). ZipWith Max [1،2،3،4،5] $ [4،5،6،7،8]. اگر این عبارت با سه پرانتز به پایان برسد ، احتمال وجود دارد که اگر آن را به ترکیب عملکرد ترجمه کنید ، سه اپراتور ترکیب خواهد داشت.
یکی دیگر از کاربردهای متداول از ترکیب عملکرد ، تعریف توابع در به اصطلاح سبک بدون نقطه (همچنین به آن سبک کمتری گفته می شود). به عنوان مثال این عملکردی را که قبلاً نوشتیم در نظر بگیرید:
XS در هر دو طرف راست قرار دارد. به دلیل انجام کاری ، می توانیم XS را از هر دو طرف حذف کنیم ، زیرا فراخوانی Foldl (+) 0 عملکردی را ایجاد می کند که لیستی را می گیرد. نوشتن تابع به عنوان sum '= foldl (+) 0 نوشتن آن را به سبک رایگان نقطه نامیده می شود. چگونه می توانیم این را به سبک رایگان بپردازیم؟
ما فقط نمی توانیم از X در هر دو طرف راست خلاص شویم. X در بدن عملکرد بعد از آن پرانتز دارد.cos (حداکثر 50) معنی ندارد. شما نمی توانید Cosine یک عملکرد را بدست آورید. کاری که ما می توانیم انجام دهیم بیان FN به عنوان ترکیبی از توابع است.
عالی! بسیاری از اوقات، یک سبک بدون نقطه خواناتر و مختصرتر است، زیرا باعث می شود به جای فکر کردن به داده ها و نحوه به هم ریختن آن ها، در مورد توابع و نوع توابع حاصل از ترکیب آنها فکر کنید. می توانید توابع ساده را انتخاب کنید و از ترکیب به عنوان چسب برای ایجاد عملکردهای پیچیده تر استفاده کنید. با این حال، بسیاری از اوقات، اگر یک تابع بیش از حد پیچیده باشد، نوشتن یک تابع به سبک آزاد نقطه کمتر قابل خواندن است. به همین دلیل است که از ساخت زنجیره های طولانی ترکیب عملکردی منع می شود، اگرچه من به دلیل اینکه گاهی اوقات بیش از حد از ترکیب خوشحال هستم، گناهکار هستم. سبک ترجیحی این است که از پیوندهای let برای برچسب زدن به نتایج میانی استفاده کنید یا مسئله را به مشکلات فرعی تقسیم کنید و سپس آن را کنار هم قرار دهید تا به جای ایجاد یک زنجیره ترکیبی عظیم، این تابع برای کسی که آن را می خواند منطقی باشد.
در بخش مربوط به نقشه ها و فیلترها، مشکل یافتن مجموع مجذورهای فرد کوچکتر از 10000 را حل کردیم. در اینجا به نظر می رسد که راه حل زمانی که در یک تابع قرار می گیرد چگونه است.
از آنجایی که از طرفداران ترکیب تابع هستم، احتمالاً اینگونه می نوشتم:
با این حال، اگر فرصتی وجود داشت که شخص دیگری آن کد را بخواند، آن را به این صورت می نوشتم:
در هیچ مسابقه گلف کد برنده نمی شود، اما کسی که تابع را می خواند احتمالا خواندن آن راحت تر از یک زنجیره ترکیب بندی است.
فارکس وکسب درامد...
ما را در سایت فارکس وکسب درامد دنبال می کنید
برچسب :
نویسنده : آرش اصل زاد
بازدید : <-PostHit->
تاريخ : سه
شنبه
30 خرداد
1402 ساعت: 14:20