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

9

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

SBI
источник
30
Независимо от того, можете ли вы или не можете, вы не должны .
Р. Мартиньо Фернандес
27
Абсолютно! Первый шаг - написать интерпретатор Lisp ;-)
Ферруччо,
Если я правильно понял, вопрос должен был касаться изучения различных понятий с помощью псевдокода без какого-либо реального языка.
SK-logic
@ SK-logic: мягко говоря, очень немногие программисты научились программировать исключительно с помощью псевдокода, большинству пришлось запачкать руки, и их лица были испорчены сообщениями об ошибках от компилятора / интерпретатора.
СБИ
4
@sbi, некоторые из лучших программистов научились программировать, когда у компиляторов вообще не было сообщений об ошибках. Кодирование на перфокартах требует небольшого понимания того, что вы делаете, задолго до того, как вы сможете запустить код. Нет необходимости упоминать, что основа для функционального программирования была создана задолго до создания первого компьютера.
SK-logic

Ответы:

21

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

Я предполагаю, что у вас есть хотя бы немного опыта в ООП; если вы это сделаете, вы должны знать, что ООП может быть сделано в C, включая полиморфизм, методы получения / установки, правила видимости и т. д. и т. д., но это довольно болезненно, и вам нужно знать как ООП, так и C внутри- чтобы снять это. То же самое с FP.

Что вы должны сделать, это сначала выучить функциональный язык программирования (у большинства из них есть удивительно простые правила синтаксиса; это не тот синтаксис, который делает их трудными для изучения), а затем позвольте вашей недавно приобретенной мудрости влиять на то, как вы пишете C.


В соответствии с запросом, некоторые вещи можно узнать из FP, а затем применить, скажем, в C, C ++ или Java:

  • Избегайте состояния, особенно общего изменяемого состояния
  • Цените чистые функции
  • Ценю ленивую оценку
  • Возможность моделировать с точки зрения глаголов, а не существительных
  • Способность подходить к проблемам рекурсивно, а также итеративно
  • Использование функций высшего порядка
  • Думая о функциях как о просто другом значении, которое вы можете передать и объединить с другими значениями
  • Использование первоклассных функций в качестве альтернативы объектно-ориентированному полиморфизму
tdammers
источник
1
Можете ли вы привести конкретные примеры того, как программисты на C / C ++ / Java могут извлечь выгоду из мудрости LISP. Это имеет смысл в теории, но я ищу что-то конкретное.
Работа
@Job, какая конкретная выгода может быть? Это расширяет их кругозор и, возможно, заставляет их думать о чрезмерном изменчивом состоянии как о плохой вещи, о чем еще можно просить?
dan_waterworth
Итак, могу ли я из этого сделать вывод, что, хотя можно изучить (некоторые) FP на C, нет смысла это делать?
СБИ
@Job: я изучил FP, когда я изучал LISP, будучи студентом много лет назад. Примерно через десять лет я применил FP в шаблонном метапрограммировании.
СБИ
1
@sbi, мой любимый способ изучения новых языков и концепций - через их реализацию. И C вполне приличный язык для реализации компилятора. Итак, да, вы можете изучать FP с C.
SK-logic
11

C может быть взломан, чтобы предложить некоторые функциональные концепции:

Этот вопрос StackOverflow расскажет вам больше. Но хотя кажется возможным заняться функциональным программированием (или большим подмножеством) в C, хаки и расширения компилятора и все, что не является лучшим способом изучения концепции.

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


Как отмечает тдаммерс в комментариях:

На самом деле, LISP, clojure и схема также являются мультипарадигмой; Haskell, будучи чистым и ленивым по умолчанию, также допускает императивное программирование, находясь в монадическом контексте, и имеет обширную поддержку параллельной обработки. Все они имеют механизмы, которые реализуют большую часть мудрости, собранной в мире ООП - инкапсуляцию, наследование, единоличную ответственность, композицию и т. Д. Вопрос не в том, ПОЗВОЛЯЕТ ли язык РАЗРЕШИТЬ другие парадигмы; это о том, какая парадигма формирует отправную точку языка.

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

Яннис
источник
Относительно вашего последнего предложения: В этом случае я бы сказал, что F # - лучший кандидат, потому что он не поймает вас в ловушку функциональности. На многопарадигмальном языке, когда вы начинаете забивать винты, вы можете просто переключиться на отвертку. Попав в ловушку одной парадигмы, вы можете пропустить разницу между винтом и гвоздем.
Р. Мартиньо Фернандес
Вопрос в том, как научиться функциональному программированию, а не программированию. Я предполагаю, что оператор имеет некоторый опыт работы с языком мультипарадигмы и хочет наиболее эффективный способ изучения функционального программирования, и в этом случае F # является хорошим кандидатом, но не идеальным. Поймать в ловушку одной парадигмы - это, очевидно, лучший способ узнать эту единственную парадигму, поскольку вам не нужно разбираться со всем, что не так.
Яннис
Я считаю, что изучение, когда парадигма хорошо подходит и когда она не подходит для определенной задачи, является частью обучения, возможно, самой важной.
Р. Мартиньо Фернандес
4
На самом деле, LISP, clojure и схема также являются мультипарадигмой; Haskell, будучи чистым и ленивым по умолчанию, также допускает императивное программирование, находясь в монадическом контексте, и имеет обширную поддержку параллельной обработки. Все они имеют механизмы, которые реализуют большую часть мудрости, собранной в мире ООП - инкапсуляцию, наследование, единоличную ответственность, композицию и т. Д. Вопрос не в том, ПОЗВОЛЯЕТ ли язык РАЗРЕШИТЬ другие парадигмы; это о том, какая парадигма формирует отправную точку языка.
tdammers
2
@MartinhoFernandes: Можно утверждать, что поймать в ловушку одной парадигмы - это идеальный способ учиться, когда в заднице действительно больно :-)
Йорг Миттаг,
2

Вы не можете изучить все аспекты функционального программирования на языке C. Но, безусловно, вы можете начать программирование функционального стиля с любого императивного языка. Эти стартовые биты - «Как сохранить чистоту во время программирования». И это может быть сделано C также. Проверьте это сообщение в блоге для деталей-

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

Gulshan
источник
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, возвращающей максимум в массиве:

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
Спасибо за этот хороший образец. Кстати, как вы определяете var info, разве это не будет journal.forEach (info)?
ejaenv
Да, это был бы подходящий вариант! :)
Михаэль Ле Барбье Грюневальд
1

Я думаю, что инструменты, которые вы используете, сильно влияют на ваше обучение. Практически невозможно выучить концепции программирования, для которых используемый вами язык программирования не предоставляет средств для использования. Конечно, вы всегда можете выучить несколько вещей, но вы не можете выучить это правильно.

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

SBI
источник
1

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

Если вы новичок в функционале, вы никогда не получите его с не функциональным языком. Скорее всего, вы научитесь делать то, что вы считаете функциональным программированием, и учиться неправильно. И всегда труднее «переучивать» вещи правильным образом, чем поначалу учить их правильно.

В любом случае, я думаю, что функционирование в C - это хорошее упражнение для тех, кто уже знает функционал. Потому что этот человек узнает, что происходит за укрытием - что на самом деле делает компьютер.

deadalnix
источник