Функциональное программирование и нефункциональное программирование - PullRequest
68 голосов
/ 23 августа 2008

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

Что такое функциональное программирование, почему и / или где я хотел бы использовать его вместо нефункционального программирования, и правильно ли я считаю, что C - это нефункциональный язык программирования?

Ответы [ 8 ]

87 голосов
/ 23 августа 2008

Одной из ключевых функций в функциональном языке является концепция первоклассных функций. Идея состоит в том, что вы можете передавать функции в качестве параметров другим функциям и возвращать их в качестве значений.

Функциональное программирование включает в себя написание кода, который не меняет состояние. Основная причина для этого состоит в том, что последовательные вызовы функции будут давать тот же результат. Вы можете написать функциональный код на любом языке, который поддерживает первоклассные функции, но есть некоторые языки, такие как Haskell, которые не позволяют вам изменять состояние. На самом деле, вы вообще не должны создавать никаких побочных эффектов (например, распечатывать текст), что может показаться совершенно бесполезным.

Вместо этого Haskell использует другой подход к IO: монады. Это объекты, которые содержат требуемую операцию ввода-вывода, которая будет выполняться на верхнем уровне вашего интерпретатора. На любом другом уровне они являются просто объектами в системе.

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

22 голосов
/ 27 января 2013

Что такое функциональное программирование

В настоящее время широко используются два различных определения «функционального программирования»:

Более старое определение (происходящее из Lisp) заключается в том, что функциональное программирование - это программирование с использованием функций первого класса, то есть когда функции обрабатываются как любое другое значение, поэтому вы можете передавать функции в качестве аргументов другим функциям, а функция может возвращать функции среди возвращаемые значения Кульминацией этого является использование функций более высокого порядка, таких как map и reduce (вы, возможно, слышали о mapReduce как об одной операции, активно используемой Google, и, что неудивительно, это близкий родственник!). Типы .NET System.Func и System.Action делают функции высшего порядка доступными в C #. Хотя каррирование нецелесообразно в C #, функции, которые принимают другие функции в качестве аргументов, являются общими, например, функция Parallel.For.

Младшее определение (популяризированное Haskell) заключается в том, что функциональное программирование также сводит к минимуму и контролирует побочные эффекты, включая мутации, то есть написание программ, которые решают проблемы путем составления выражений. Это чаще называют «чисто функциональным программированием». Это стало возможным благодаря совершенно разным подходам к структурам данных, называемым «чисто функциональными структурами данных». Одна из проблем заключается в том, что перевод традиционных императивных алгоритмов на использование чисто функциональных структур данных обычно снижает производительность в 10 раз. Haskell - единственный сохранившийся чисто функциональный язык программирования, но концепции проникли в массовое программирование с такими библиотеками, как Linq в .NET.

где бы я хотел использовать его вместо нефункционального программирования

Везде. Лямбды в C # теперь продемонстрировали большие преимущества. C ++ 11 имеет лямбды. Там нет оправдания, чтобы не использовать функции более высокого порядка сейчас. Если вы можете использовать такой язык, как F #, вы также получите выгоду от вывода типов, автоматического обобщения, каррирования и частичного применения (а также множества других языковых функций!).

Правильно ли я считаю, что C - это нефункциональный язык программирования?

Да. С является процедурным языком. Тем не менее, вы можете получить некоторые преимущества функционального программирования, используя указатели функций и void * в C.

6 голосов
/ 23 августа 2008

Может быть стоит проверить эту статью на F # "101" на недавно опубликованном CoDe Mag.

Кроме того, У Дастина Кэмпбелла есть отличный блог , где он опубликовал множество статей о своих приключениях по освоению скорости с F # ..

Надеюсь, вы найдете это полезным:)

EDIT:

Кроме того, я хочу добавить, что мое понимание функционального программирования заключается в том, что все является функцией или параметрами функции, а не экземплярами / объектами с состоянием. я хочу попасть, но просто не хватает времени! :)

4 голосов
/ 18 февраля 2009

Пример кода Джона Статистика не показывает функциональное программирование, потому что, когда вы занимаетесь функциональным программированием, ключ в том, что код НЕ УКАЗЫВАЕТСЯ (record = thingConstructor(t) является назначением), и у него НЕТ ПОБОЧНЫХ ЭФФЕКТОВ (localMap.put(record) это утверждение с побочным эффектом). В результате этих двух ограничений все, что делает функция , полностью фиксируется ее аргументами и возвращаемым значением. Переписать код Statistician так, как он должен выглядеть, если вы хотите эмулировать функциональный язык с использованием C ++:

RT getOrCreate(const T thing, 
                  const Function<RT<T>> thingConstructor, 
                  const Map<T,RT<T>> localMap) {
    return localMap.contains(t) ?
        localMap.get(t) :
        localMap.put(t,thingConstructor(t));
}

В результате применения правила отсутствия побочных эффектов каждый оператор является частью возвращаемого значения (следовательно, return приходит first ), а каждый оператор является выражением. В языках, которые обеспечивают функциональное программирование, подразумевается ключевое слово return, а оператор if ведет себя как оператор C ++ * ?:.

Кроме того, все является неизменным, поэтому localMap.put должен создать новую копию localMap и вернуть ее вместо изменения исходного localMap , как в обычном C ++ или Ява программа будет. В зависимости от структуры localMap копия может повторно использовать указатели на оригинал, уменьшая объем копируемых данных.

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

Однако функциональные программы, как правило, работают медленно (из-за того, что им приходится копировать), и они не очень хорошо взаимодействуют с другими программами, процессами операционной системы или операционными системами, которые работают с адресами памяти, байтовые байты с прямым порядком байтов и другие машинно-зависимые нефункциональные биты. Степень неинтероперабельности имеет тенденцию обратно коррелировать со степенью функциональной чистоты и строгостью системы типов.

Более популярные функциональные языки имеют действительно очень строгие системы типов. В OCAML вы даже не можете смешивать целочисленные значения и математические вычисления с плавающей точкой или использовать одни и те же операторы (+ - для добавления целых чисел, + - для добавления чисел с плавающей запятой). Это может быть как преимуществом, так и недостатком, в зависимости от того, насколько высоко вы цените способность средства проверки типов обнаруживать ошибки определенного типа.

Функциональные языки также имеют тенденцию иметь действительно большие среды выполнения. Haskell является исключением (исполняемые файлы GHC почти такие же маленькие, как программы на C, как во время компиляции, так и во время выполнения), но программы SML, Common Lisp и Scheme всегда требуют тонны памяти.

3 голосов
/ 23 августа 2008

Я предпочитаю использовать функциональное программирование, чтобы спасти себя от повторяющейся работы, создав более абстрактную версию, а затем используя ее. Позвольте мне привести пример. В Java я часто создаю карты для записи структур и, следовательно, пишу структуры getOrCreate.

SomeKindOfRecord<T> getOrCreate(T thing) { 
    if(localMap.contains(t)) { return localMap.get(t); }
    SomeKindOfRecord<T> record = new SomeKindOfRecord<T>(t);
    localMap = localMap.put(t,record);
    return record; 
}

Это случается очень часто. Теперь на функциональном языке я мог написать

RT<T> getOrCreate(T thing, 
                  Function<RT<T>> thingConstructor, 
                  Map<T,RT<T>> localMap) {
    if(localMap.contains(t)) { return localMap.get(t); }
    RT<T> record = thingConstructor(t);
    localMap = localMap.put(t,record);
    return record; 
}

и мне никогда больше не пришлось бы писать новый, я мог бы унаследовать его. Но я мог бы сделать лучше, чем наследовать, я мог бы сказать в конструкторе этой вещи

getOrCreate = myLib.getOrCreate(*,
                                SomeKindOfRecord<T>.constructor(<T>), 
                                localMap);

(где * это своего рода нотация «оставьте этот параметр открытым», которая является своего рода карри)

и затем локальный getOrCreate точно такой же, как если бы я выписал все это в одну строку без зависимостей наследования.

3 голосов
/ 23 августа 2008

Да, вы правы, считая, что C - это нефункциональный язык. C - процедурный язык.

2 голосов
/ 23 августа 2008

Если вы ищете хороший текст на F #

Эксперт F # написан в соавторстве с Доном Саймом. Создатель F #. Он работал над дженериками в .NET специально, чтобы он мог создавать F #.

F # смоделирован после OCaml, поэтому любой текст OCaml также поможет вам выучить F #.

1 голос
/ 07 января 2016

Я считаю Что такое функциональное программирование? полезно

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

Предпочитаю явное when param

public Program getProgramAt(TVGuide guide, int channel, Date when) {
  Schedule schedule = guide.getSchedule(channel);

  Program program = schedule.programAt(when);

  return program;
}

над

public Program getCurrentProgram(TVGuide guide, int channel) {
  Schedule schedule = guide.getSchedule(channel);

  Program current = schedule.programAt(new Date());

  return current;
}

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

...