Чи можете ви вивчити функціональне програмування на C? [зачинено]


9

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


30
Що стосується того, можна чи не можна, не слід .
Р. Мартіньо Фернандес

27
Абсолютно! Перший крок - написати перекладача Ліспа ;-)
Ферруччо

Якби я правильно зрозумів, питання повинно було стосуватися вивчення різних понять з псевдокодом, без жодної реальної мови.
SK-логіка

@ SK-логіка: м'яко кажучи, мало хто з програмістів навчився програмуванню виключно за допомогою псевдокоду, більшості довелося забруднити руки, а обличчя зіпсовано повідомленнями про помилки компілятора / інтерпретатора.
sbi

4
@sbi, деякі з найкращих програмістів навчилися програмуванню, коли у компіляторів взагалі не було повідомлень про помилки. Кодування на перфокартах потребує трохи розуміння того, що ви робите задовго до того, як у вас буде шанс запустити код. І зайве згадувати, що основа функціонального програмування була створена задовго до того, як був побудований перший комп'ютер.
SK-логіка

Відповіді:


21

Очевидно, що ви можете зайняти функціональним програмуванням в C. Теоретично ви також можете вивчити принципи функціонального програмування в C, але мова не робить це легким.

Я припускаю, що у вас є хоча б трохи досвіду в OOP; якщо це так, ви повинні знати, що OOP можна робити в C, включаючи поліморфізм, геттери / сетери, правила видимості тощо тощо, але це досить болісно, ​​і вам потрібно знати як OOP, так і C всередині - витягнути його. Так само і з FP.

Що ви повинні зробити, це спочатку вивчити функціональну мову програмування (більшість з них має напрочуд прості правила синтаксису; не синтаксис змушує їх засвоювати), а потім дозвольте новоспеченій мудрості впливати на те, як ви пишете C.


За запитом, кілька речей, які ви можете дізнатися з FP, а потім застосувати у, скажімо, C, C ++ або Java:

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

1
Чи можете ви надати конкретні приклади того, як C / C ++ / Java програмісти можуть отримати користь від мудрості LISP. В теорії це має сенс, але я шукаю щось конкретне.
робота

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

Тож чи можу я зробити з цього висновок, що, хоча можна вивчити (якусь) ПП в С, цього немає сенсу робити?
sbi

@Job: Я вивчив FP, коли я вивчив LISP ще студентом багато років тому. Приблизно через десятиліття я застосував FP в мета-програмуванні шаблонів.
sbi

1
@sbi, мій улюблений спосіб вивчення нових мов та концепцій - це реалізація їх. І C - цілком гідна мова для реалізації компілятора. Так, так, ви можете вивчити FP за допомогою C.
SK-логіка

11

C можна зламати, пропонуючи деякі функціональні концепції:

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

Для того, щоб насправді вивчити функціональне програмування, найкращим є одна з відомих функціональних мов програмування, як Lisp та його діалекти ( Clojure , Scheme ), Erlang та Haskell . Будь-яка з них - це ідеальні інструменти, які працюють в рамках функціонального мислення програмування. F # також є хорошим кандидатом, якщо у вас є .Net фон, але це багатомовна парадигма, а не суто функціональна мова програмування.


Як зазначає tdammers у коментарях:

Власне, LISP, кложур та схема - також багатопарадигма; Хоча Haskell, будучи чистим і ледачим за замовчуванням, також забезпечує імперативне програмування, перебуваючи в монадійному контексті, і має широку підтримку одночасної обробки. Все це має механізми, які реалізують велику частину мудрості, зібраної у світі ООП - інкапсуляція, успадкування, одноосібна відповідальність, склад тощо. Це не стільки в тому, чи ВІДМОВАЄ мова інших парадигм; йдеться про те, яка парадигма формує мовну точку відліку.

Наскільки мені відомо , Lisp і його діалекти і Erlang є кращими кандидатами , ніж F # , тому що вони стимулюють функціональне програмування по порівнянні з іншими парадигмами, ніж tdammers красиво , як то кажуть , за відправну точку мови . F # включає функціональне програмування, але не заохочує його в порівнянні з іншими підтримуваними парадигмами, імперативом та програмуванням oo.


Стосовно вашого останнього речення: У такому випадку я б заперечував, що F # - кращий кандидат, оскільки він не вловить вас у функціональному настрої. Мовою, що містить багато парадигми, коли ви починаєте забивати гвинти, ви можете просто перейти на викрутку. Потрапивши в одну парадигму, ви можете пропустити різницю між гвинтом і цвяхом.
Р. Мартіньо Фернандес

Ну питання в тому, як навчитися функціональному програмуванню, а не програмуванню. Я припускаю, що оп має певний досвід роботи з мовою мульти парадигми і хоче найефективніший спосіб вивчити функціональне програмування, і в цьому випадку F # є хорошим кандидатом, але не ідеальним. У пастці в одній парадигмі, очевидно, найкращий спосіб, коли ви шукаєте дізнатися про цю єдину парадигму, оскільки вам не доведеться мати справу з усім, що це не так.
янніс

Я вважаю, що навчання, коли парадигма добре підходить і коли вона погано підходить для певного завдання, є частиною її вивчення, можливо, найважливішим.
Р. Мартіньо Фернандес

4
Власне, LISP, кложур та схема - також багатопарадигма; Хоча Haskell, будучи чистим і ледачим за замовчуванням, також забезпечує імперативне програмування, перебуваючи в монадійному контексті, і має широку підтримку паралельної обробки. Все це має механізми, які реалізують велику частину мудрості, зібраної у світі ООП - інкапсуляція, успадкування, одноосібна відповідальність, склад тощо. Це не стільки в тому, чи ВІДМОВАЄ мова інших парадигм; йдеться про те, яка парадигма формує мовну точку відліку.
tdammers

2
@MartinhoFernandes: Можна стверджувати, що потрапляння в пастку в єдиній парадигмі - це ідеальний спосіб дізнатися, коли це насправді біль у попці :-)
Jörg W Mittag

2

Ви не можете вивчити всі аспекти функціонального програмування в C. Але, безумовно, ви можете почати програмування функціонального стилю з будь-якої необхідної мови. Ці початкові біти - "Як зберегти чистоту при програмуванні". І це також можна зробити C. Перегляньте цю публікацію в блозі, щоб отримати детальну інформацію-

http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/


2

TL; DR

Функціональне програмування стосується закриттів та їх застосування. Якщо хтось не зможе показати вам бібліотеку закриття походження для 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 whatx`.

Ще одне типове використання закриттів - визначення часткових застосувань функцій. Припустимо, що у нас є система звітності, аналогічна 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;
}

Повернене значення - це закриття, яке може бути використане для обчислення значення або отримання іншого разу, якщо воно вже було обчислено.

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

Висновок

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


1
Дякую за цей приємний зразок. BTW, як ви визначаєте var інформацію, чи не це буде journal.forEach (info)?
ejaenv

Так, це був би відповідний варіант! :)
Майкл Ле Барб'є Грюневальд

1

Я думаю, що інструменти, якими ви користуєтесь, багато впливають на ваше навчання. Вивчити поняття програмування, для яких використовувана мова програмування майже неможливо, не забезпечує можливості їх використання. Звичайно, ви завжди можете дізнатися кілька речей, але ви не можете навчитися належним чином.

Але це все одно академічно, тому що, як каже Мартиньо у своєму коментарі , навіть якщо ви могли вивчити функціональне програмування, ви не повинні намагатися цього робити, адже є мови, де це набагато простіше.


1

Ви не повинні вивчати функціональне програмування на мові C, але строго функціональною мовою (Haskell, Caml, Erlang та ін.).

Якщо ви новачок у функціоналі, ви ніколи не отримаєте це з нефункціональною мовою. Швидше за все, ви будете навчати себе робити те, що, на вашу думку, є функціональним програмуванням і навчитися речі не так. І завжди важче «навчити» речі правильно, ніж спочатку навчитися їх правильно.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.