Суть функціонального програмування

Для повного розуміння функціонального програмування необхідно разбана в його чотирьох основних характеристиках (http://enwikipediaorg/wiki/ Functional_programming)

•&nbsp&nbsp Функції вищого порядку Дозволяють визначати функції у вигляді аргументів і повертати їх у вигляді результатів Це дозволяє виконувати з функціями опацію каррінг, як буде пояснено далі

•&nbsp&nbsp Чисті функції Концепція чистої функції повязана з програмуванням, вільним від побічних ефектів Загалом, вона зводиться до того, що чистий функція з чистими аргументами не намагатиметься до різних результатів при різних порядках обчислення Скажімо, що ми викликали функцію X один раз, а потім викликали її з тими ж аргументами знову Другий виклик функції не повинен залежати від першого Результати, що видаються функцією X, завжди одаковие, незалежно від того, скільки разів вона викликається

•&nbsp&nbsp Рекурсія Операція циклу виконується за допомогою рекурсії, коли функція здійснює обчислення і для обчислення наступного елементу викликає су себе

•&nbsp&nbsp Обчислення функції У функціональному мові програмування спосіб Вісленев функції є важливим, тому що це допомагає визначити типи допуімих операцій

Розглянемо кожну з цих характеристик функціонального мови программіранія в контексті мови С #

Як було згадано раніше, функції вищого порядку дозволяють виконання опаціі каррінга1 (currying) Брайан Бекман (Brian Beckman) у своєму блозі

‘Менш поширеним перекладом цього терміна на російську мову є каррірованіе – Пер

(http://weblogsaspnet/brianbec/archive/2OO6/O6/Ol/Lambdas_2COO_-Closures_2COO_

-Currying_2C00_-and-All-Thataspx)  дає наступне пояснення каррінг:

“Це називається каррінг Більш точно, каррінг являє собою воожность мови (або просто теоретичний конструктив), яка позволт викликати функцію по одному аргументу за раз, зліва направо за списком аументов Кожен виклик повертає нову функцію, яка приймає залишилися аргументи, до тих пір, поки у нас не залишиться функція одного аргументу Користь цієї можливості полягає не тільки в прикрашанні сценаріїв, подібних цьому, але також у підтримці простого теоретичного обчислення програмування, в якому кожна функція внутрішньо є функцією лише одного аргументу, хоча може і повертати інші функції У такому обчисленні функція багатьох змінних – мультіарная функція – моделюється у вигляді ланцюжка унарних функцій Звичайно ж, даними перелічив є лямбда-числення .

По правді кажучи, незалежно від того, яке пояснення каррінг ви візьмете, всі вони абсолютно заплутані, а практичне пояснення, навіщо потрібно його ісполовать, взагалі важко знайти

Попросту, каррінг дозволяє визначати функції, що містять стан і іользуемие для обчислення інших функцій Щоб допомогти вам зрозуміти концеію каррінг, ми розглянемо два приклади: один чисто теоретичний, Пояснюють подробиці картингу, а інший – практичний, у якому обчислюється податок з продажів

Теоретичний приклад

Каррінг для функцій був можливий у більш ранніх версіях мови С #, але код для його реалізації був досить складним З появою в мові лямбда-виразів написання функцій з каррінг стало досить легким завданням Коротенько, проіодная функція (curried function) являє собою функцію з додатковою можливістю, про яку клієнт функції не знає Таке оснащення функції долнітельной можливістю ще називаєтьсядекоруванням функції(decorating a  function)

Уявіть собі ситуацію, коли потрібно згенерувати рядок, вміщену в інший текст При цьому ви не хочете, щоб викликає клієнт знав подробнті декорування рядки, ви просто хочете, щоб це було зроблено Дану зачу можна вирішити за допомогою наступного лямбда-вирази:

(surrounding, core) =&gt surrounding + &quot_&quot + core + &quot_&quot + surrounding

/ / (Навколишній, внутрішній) => навколишній + _ + Внутрішній + _ +

/ / Навколишній

Клієнт, що викликає дане лямбда-вираз, використовував би код, подібний наступному, за умови, що лямбда-вираз було присвоєно змінному висловом:

expression(&quot+++&quot, &quothello&quot)

Клієнт, що викликає вираз, не знає, які дії вираз предпрінімт для побудови рядка, але знає окремі компоненти рядка Проблема з цим виразом полягає в тому, що воно не така зручне, т к лямбдираженію необхідно постійно надавати всі параметри Оскільки перший параметр при виконанні програми не змінюється занадто часто, то він ідеал підходить для перетворення в змінну

ПРИМІТКА

Параметр и дл я лямбда-виразів називаютьсяжорстко-закодованими,т к вони є строковими буферами, а не змінними Жорстко-закодованим і паретрамі також можуть бути числа або любі е інші значення, які вставляються в вихідний код Жорстко-закодовані параметри можуть бути проблемними, якщо використовувати одне і те ж значення в декількох місцях коду У такому випадку, щоб змінити такий параметр, необхідно знайти всі його випадки в коді, що може бути не так і просто

Перший параметр можна перетворити в змінну, до якої можна звертатись з різних ділянок коду, як показано в наступному коді:

string surrounding = &quot+++" expression(surrounding, &quothello&quot)

Написання коду з використанням параметрів не є проблемою Але тепер нам потрібно всюди тягати загальний параметр, що може швидко стати дуже ндобним Ми хочемо створити рядок, але не хочемо дбати про подробиці цієї операції Ось чому обєктно-орієнтоване програмування стало таким популярним Тут ми можемо переносити всюди просте посилання на обєкт, Корая знає, яким чином обробляти подробиці

А у функціональному програмуванні застосовується підхід похідних фуній, при якому створюється функція, яка має стан і буде належним чином викликати необхідний метод Похідну функцію можна створити з пощью наступного лямбда-вирази:

surrounding =&gt core =&gt surrounding + &quot &quot + core + &quot  &quot + surrounding,-

З першого погляду це лямбда-вираз може здатися страхітливим, але в порівнянні з наступною версією анонімного методу воно досить просте:

delegate (string surrounding) { return delegate (string core) {

return surrounding + &quot &quot + core + &quot &quot + surrounding

}

}

Ми створюємо анонімний метод в анонімному методі, отримуючи два рівня викликів, або функцію вищого порядку, що характерно для функціонального программованія

У випадку з лямбда-виразами, які повертають лямбда-вирази, визначення лямбда-виразу може бути кілька мудро Повне оголошення проізвоітся функції наводиться в наступному коді:

Func&ltstring, Func&ltstring, string» curry =

surrounding =&gt core =&gt surrounding + &quot &quot + core + &quot &quot + surrounding

Ми передаємо строкове значення і отримуємо лямбда-вираз, який принавши строкове значення і повертає строкове значення

Похідна функція викликається таким чином:

curry(&quot+++&quot)(&quothello&quot)

Цей спосіб виклику похідної функції схожий на використання лямбдираженія, показаного на початку цього розділу, тільки замість коми пріменть дужки Це тому, що ми викликаємо функцію, що повертає функцію, яку можна викликати знову

Перевага такого підходу полягає в тому, що можна створити лямбдираженіе, яке можна присвоїти змінної і викликати його пізніше Така СХА дозволяє уникнути необхідності переносити всюди перший параметр, т к він вбудований в перший виклик методу, як показано в наступному коді:

Func&ltstring, string&gt curriedFunction = curry(&quot+++&quot) curriedFunction(&quothello&quot)

Мінлива curriedFunction містить стан При її виклику метод генерує рядок, точно так, як це робилося початковим лямбда-виразом, показаний на початку цього розділу

Практичний приклад: обчислення податку з продажів

Академічні приклади допомагають зрозуміти, що можливість робить на техничку рівні, але не дають ніякої допомоги у вирішенні справжніх проблем Тому розглянемо практичну проблему обчислення податку з продажів і загальну суму при купівлі товарів При традиційному підході, першою справою розробляється ідея податку з продажів у вигляді інтерфейсу, як показано в наступному коді:

interface ICalculate { double SalesTax { get }

double Calculate(double total)

}

Даний інтерфейс має властивість SalesTax, яке представляє поточний Урень податку з продажів, і метод Calculatef), який обчислює загальну суму пупки, що включає податок з продажів Реалізація інтерфейсу ICalculate може бути виконана таким чином:

class LocalSalesTax : ICalculate { double _salesTax

public LocalSalesTax(double amount) {

_salesTax = amount

}

public double SalesTax { get { return _salesTax }

}

public double Calculate(double total) { return total + total * SalesTax

}

}

Реалізація класу LocalsaiesTax має параметр конструктора, який опредяет рівень податку з продажів У наступному коді обчислюється податок з продажів для рівня податку в 16,5%:

ICalculate country = new LocalSalesTax(0165) double amount = 1000

ConsoleWriteLine (Я купив товарів на суму ( + amount +

“), А загальна сума з податком буде ( + countryCalculate (amount) + ))

Даний інтерфейс, його реалізація і застосування демонструють рішення прлеми допомогою підходу імперативного програмування

Тепер подивимося, як та ж проблема вирішується застосуванням підходу функціального програмування:

Func&ltdouble, Func&ltdouble, double» salesTax =

localSalesTax =&gt totalBought =&gt totalBought + totalBought * localSalesTax

Func&ltdouble, double&gt country = salesTax(0165) double amount = 1000

ConsoleWriteLine (Я купив товарів на суму ( + amount +

“) А загальна сума з податком буде ( + country (amount) + ))

Насамперед, зверніть увагу, наскільки компактніше цей код – всього лише 8 рядків Функціональний код набагато компактніші тому, що він тільки вирішує проблему і не робить нічого зайвого Мінлива salesTax є похідною функцією, яка обчислює податок з продажів на основі суми, переданої встрнной функції А змінна country представляє обчислення податку з продажів для певної країни

Джерело: Гросс К С # 2008: Пер з англ – СПб: БХВ-Петербург, 2009 – 576 е: ил – (Самовчитель)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*