В результаті обговорення тут коментарів мені цікаво, чи можна навчитися функціональному програмуванню на С?
В результаті обговорення тут коментарів мені цікаво, чи можна навчитися функціональному програмуванню на С?
Відповіді:
Очевидно, що ви можете зайняти функціональним програмуванням в C. Теоретично ви також можете вивчити принципи функціонального програмування в C, але мова не робить це легким.
Я припускаю, що у вас є хоча б трохи досвіду в OOP; якщо це так, ви повинні знати, що OOP можна робити в C, включаючи поліморфізм, геттери / сетери, правила видимості тощо тощо, але це досить болісно, і вам потрібно знати як OOP, так і C всередині - витягнути його. Так само і з FP.
Що ви повинні зробити, це спочатку вивчити функціональну мову програмування (більшість з них має напрочуд прості правила синтаксису; не синтаксис змушує їх засвоювати), а потім дозвольте новоспеченій мудрості впливати на те, як ви пишете C.
За запитом, кілька речей, які ви можете дізнатися з FP, а потім застосувати у, скажімо, C, C ++ або Java:
C можна зламати, пропонуючи деякі функціональні концепції:
Це питання StackOverflow розповість вам більше. Але хоча здається, що можливо робити функціональне програмування (або великий підмножина) в C, хаки та розширення компілятора і все, що не є найкращим способом дізнатися про концепцію.
Для того, щоб насправді вивчити функціональне програмування, найкращим є одна з відомих функціональних мов програмування, як Lisp та його діалекти ( Clojure , Scheme ), Erlang та Haskell . Будь-яка з них - це ідеальні інструменти, які працюють в рамках функціонального мислення програмування. F # також є хорошим кандидатом, якщо у вас є .Net фон, але це багатомовна парадигма, а не суто функціональна мова програмування.
Як зазначає tdammers у коментарях:
Власне, LISP, кложур та схема - також багатопарадигма; Хоча Haskell, будучи чистим і ледачим за замовчуванням, також забезпечує імперативне програмування, перебуваючи в монадійному контексті, і має широку підтримку одночасної обробки. Все це має механізми, які реалізують велику частину мудрості, зібраної у світі ООП - інкапсуляція, успадкування, одноосібна відповідальність, склад тощо. Це не стільки в тому, чи ВІДМОВАЄ мова інших парадигм; йдеться про те, яка парадигма формує мовну точку відліку.
Наскільки мені відомо , Lisp і його діалекти і Erlang є кращими кандидатами , ніж F # , тому що вони стимулюють функціональне програмування по порівнянні з іншими парадигмами, ніж tdammers красиво , як то кажуть , за відправну точку мови . F # включає функціональне програмування, але не заохочує його в порівнянні з іншими підтримуваними парадигмами, імперативом та програмуванням oo.
Ви не можете вивчити всі аспекти функціонального програмування в C. Але, безумовно, ви можете почати програмування функціонального стилю з будь-якої необхідної мови. Ці початкові біти - "Як зберегти чистоту при програмуванні". І це також можна зробити C. Перегляньте цю публікацію в блозі, щоб отримати детальну інформацію-
http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/
Функціональне програмування стосується закриттів та їх застосування. Якщо хтось не зможе показати вам бібліотеку закриття походження для C, забудьте про використання C для вивчення функціонального програмування.
Кардинальна концепція функціонального програмування - це поняття про закриття, яке, грубо кажучи, фіксує функцію разом із прив'язкою змінних. Окрім розповсюдженого використання замикань, у функціональному програмуванні є ще кілька відмінних рис, як-от використання рекурсивних функцій та незмінних значень (обидва добре грають разом). Ці риси - це питання культури більше, ніж будь-що інше, і немає технічних перешкод використовувати їх практично будь-якою мовою, тому я у своїй відповіді зосереджуюсь на закриттях: не кожна мова дозволяє легко створювати закриття.
Типовим способом закриття є реалізація механізмів конфіденційності. Наприклад, код Javascript - у прикладах, які я вибрав Javascript, оскільки це функціональна мова з так званим "C-подібним синтаксисом", і ваше запитання говорить про те, що ви знайомі з C:
create_counter = function()
{
var x = 0;
var counter = function()
{
++x;
return x;
};
return counter;
}
Тоді с
a = create_counter();
b = create_counter();
ми маємо дві функції a
і b
рахуємо непересічні колекції. Суть прикладу полягає в тому, що змінні x
фіксуються закриттям, що визначає counter
закриття, і кожен раз, коли відбувається нове counter
закриття is instantiated by the function, it gets its fresh own idea of what
x`.
Ще одне типове використання закриттів - визначення часткових застосувань функцій. Припустимо, що у нас є система звітності, аналогічна syslog
реалізації функції
var log = function(priority, message) {
…
};
де аргументи priority
і , message
як очікується, будуть рядки, перший з яких один з "debug"
, "info"
і так далі. Ми можемо визначити фабрику журналів так:
var logWithPriority = function(priority) {
return function(message) {
log(priority, message);
};
};
і використовувати його для визначення спеціалізованих версій нашого журналу:
var debug = logWithPriority("debug");
var info = logWithPriority("info");
…
Це дуже корисно, тому що замість того, щоб писати схильні до for
помилок -колачі, як це
for(i = 0; i < journal.length; ++i) {
log("info", journal[i]);
}
ми можемо написати чистіше, коротше і набагато простіше (немає i
, це набагато краще):
journal.forEach(logWithPriority("info"));
Третє важливе поле для закриття - здійснення лінивої оцінки - зауважте, що спеціальна підтримка мови може забезпечити кращу реалізацію.
Ледача функція замість того, щоб виконувати прямі обчислення, повертає закриття, яке можна викликати (або "примусити" в жаргоні лінь) для виконання питання. Мотивація для цього полягає в тому, що він розділяє підготовку обчислення та проведення обчислення. Практичним прикладом цього є регулярна компіляція виразів: якщо програма збирає багато регулярних виразів під час запуску, для запуску знадобиться багато часу. Якщо замість цього ми ліниво компілюємо регулярні вирази і змушуємо їх у міру необхідності, то наша програма може швидко запуститися. Звичайно, регулярні вирази можуть бути замінені тут будь-якою структурою, яка потребує значного часу ініціалізації.
Ось як реалізувати ледачу оцінку із закриттями. Розглянемо класичну реалізацію функції arrayMax, що повертає max у масиві:
function arrayMax(array) {
return array.reduce(function(a, b) {
return Math.min(a, b);
};
}
Ледачий варіант буде:
function arrayMax(array) {
var memo = null;
function actuallyCompute() {
if(memo === null) {
memo = array.reduce(function(a, b) {
return Math.min(a, b);
});
}
return memo;
}
return actuallyCompute;
}
Повернене значення - це закриття, яке може бути використане для обчислення значення або отримання іншого разу, якщо воно вже було обчислено.
Маючи ці три приклади, ми повинні бути впевнені, що закриття та їх застосування є стрижнем функціонального програмування.
Навчання функціонального програмування означає навчитися програмувати із закриттями. Як наслідок, мови, що дозволяють легко маніпулювати закриттями, і особливо часткове застосування функцій, слід враховувати під час пошуку мови для вивчення функціонального програмування. І навпаки, мови, де закриттями не може бути легко маніпулювати, було б поганим вибором.
Я думаю, що інструменти, якими ви користуєтесь, багато впливають на ваше навчання. Вивчити поняття програмування, для яких використовувана мова програмування майже неможливо, не забезпечує можливості їх використання. Звичайно, ви завжди можете дізнатися кілька речей, але ви не можете навчитися належним чином.
Але це все одно академічно, тому що, як каже Мартиньо у своєму коментарі , навіть якщо ви могли вивчити функціональне програмування, ви не повинні намагатися цього робити, адже є мови, де це набагато простіше.
Ви не повинні вивчати функціональне програмування на мові C, але строго функціональною мовою (Haskell, Caml, Erlang та ін.).
Якщо ви новачок у функціоналі, ви ніколи не отримаєте це з нефункціональною мовою. Швидше за все, ви будете навчати себе робити те, що, на вашу думку, є функціональним програмуванням і навчитися речі не так. І завжди важче «навчити» речі правильно, ніж спочатку навчитися їх правильно.
У будь-якому разі, я думаю, що функціонування в C - це хороша вправа для того, хто вже знає функціонал. Тому що ця людина дізнається, що відбувається за капотом - що справді робить комп’ютер.