Я читал статьи в Википедии как о процедурном программировании, так и о функциональном программировании , но я все еще немного сбит с толку. Может ли кто-нибудь свести это до глубины души?
247
Я читал статьи в Википедии как о процедурном программировании, так и о функциональном программировании , но я все еще немного сбит с толку. Может ли кто-нибудь свести это до глубины души?
Ответы:
Функциональный язык (в идеале) позволяет вам написать математическую функцию, то есть функцию, которая принимает n аргументов и возвращает значение. Если программа выполняется, эта функция логически оценивается при необходимости. 1
С другой стороны, процедурный язык выполняет ряд последовательных шагов. (Существует способ преобразования последовательной логики в функциональную логику, называемый стилем передачи продолжения .)
Как следствие, чисто функциональная программа всегда дает одно и то же значение для ввода, и порядок оценки не является четко определенным; Это означает, что неопределенные значения, такие как пользовательский ввод или случайные значения, трудно моделировать на чисто функциональных языках.
+1 Как и все остальное в этом ответе, это обобщение. Это свойство, вычисляющее вычисление, когда требуется его результат, а не последовательно, где оно вызывается, называется «лень». Не все функциональные языки на самом деле являются универсально ленивыми, и лень не ограничивается функциональным программированием. Скорее, приведенное здесь описание предоставляет «ментальную основу» для размышления о разных стилях программирования, которые не являются отдельными и противоположными категориями, а скорее текучими идеями.
источник
В основном два стиля, как Инь и Ян. Один организован, а другой хаотичен. Бывают ситуации, когда функциональное программирование является очевидным выбором, а в других ситуациях процедурное программирование является лучшим выбором. Вот почему есть как минимум два языка, которые недавно выпустили новую версию, которая охватывает оба стиля программирования. ( Perl 6 и D 2 )
Процедурный:
Perl 6
Д 2
Функциональность:
Haskell
(скопировано из Википедии );
или в одну строку:
Perl 6
Д 2
Примечание:
Факториал на самом деле является распространенным примером, показывающим, как легко создавать новые операторы в Perl 6 так же, как вы создаете подпрограмму. Эта функция настолько укоренилась в Perl 6, что большинство операторов в реализации Rakudo определяются таким образом. Это также позволяет вам добавлять свои собственные несколько кандидатов в существующие операторы.
Этот пример также показывает создание диапазона (
2..$n
) и мета-оператор сокращения списка ([ OPERATOR ] LIST
) в сочетании с оператором умножения числового инфикса. (*
)Это также показывает, что вы можете поставить
--> UInt
подпись вместоreturns UInt
нее.(Вы можете избежать запуска диапазона с помощью, так
2
как «оператор» умножения вернется1
при вызове без каких-либо аргументов)источник
sub postfix:<!> ($n) { [*] 1..$n }
No operation can have side effects
ли вы уточнить это?sub foo( $a, $b ){ ($a,$b).pick }
← не всегда возвращает один и тот же вывод для одного и того же ввода, в то время как следующее возвращаетsub foo( $a, $b ){ $a + $b }
Я никогда не видел это определение, данное в другом месте, но я думаю, что это довольно хорошо суммирует различия, приведенные здесь:
Функциональное программирование фокусируется на выражениях
Процедурное программирование фокусируется на утверждениях
У выражений есть значения. Функциональная программа - это выражение, значение которого представляет собой последовательность инструкций для компьютера.
Утверждения не имеют значений и вместо этого изменяют состояние некоторой концептуальной машины.
В чисто функциональном языке не было бы операторов, в том смысле, что нет никакого способа манипулировать состоянием (у них все еще может быть синтаксическая конструкция с именем «оператор», но если бы он не манипулировал состоянием, я бы не назвал его оператором в этом смысле ). На чисто процедурном языке не было бы никаких выражений, все было бы инструкцией, которая манипулирует состоянием машины.
Хаскель был бы примером чисто функционального языка, потому что нет способа манипулировать состоянием. Машинный код был бы примером чисто процедурного языка, потому что все в программе - это оператор, который манипулирует состоянием регистров и памятью машины.
Смущает то, что подавляющее большинство языков программирования содержат как выражения, так и операторы, что позволяет смешивать парадигмы. Языки могут быть классифицированы как более функциональные или процедурные в зависимости от того, насколько они поощряют использование выражений против выражений.
Например, C был бы более функциональным, чем COBOL, потому что вызов функции - это выражение, тогда как вызов подпрограммы в COBOL - это оператор (который манипулирует состоянием общих переменных и не возвращает значение). Python будет более функциональным, чем C, потому что он позволяет вам выражать условную логику как выражение, используя оценку короткого замыкания (test && path1 || path2 в отличие от операторов if). Схема будет более функциональной, чем Python, потому что все в схеме является выражением.
Вы по-прежнему можете писать в функциональном стиле на языке, который поощряет процессуальную парадигму и наоборот. Просто сложнее и / или более неловко писать в парадигме, которая не поощряется языком.
источник
В информатике функциональное программирование - это парадигма программирования, которая рассматривает вычисления как оценку математических функций и избегает состояния и изменчивых данных. Он подчеркивает применение функций, в отличие от процедурного стиля программирования, который подчеркивает изменения в состоянии.
источник
GetUserContext()
бы функцию, пользовательский контекст был бы передан. Это функциональное программирование? Заранее спасибо.Функциональное программирование
Процедурное программирование
function_to_add_one
это функцияprocedure_to_add_one
это процедураДаже если вы запустите функцию пять раз, каждый раз она будет возвращаться 2
Если вы запустите процедуру пять раз, в конце пятого прогона вы получите 6 .
источник
Я считаю, что процедурное / функциональное / объективное программирование - это то, как подходить к проблеме.
Первый стиль будет планировать все по шагам и решать проблему путем реализации одного шага (процедуры) за раз. С другой стороны, в функциональном программировании акцент делается на подходе «разделяй и властвуй», когда проблема делится на подзадачу, затем решается каждая подзадача (создается функция для решения этой подзадачи) и результаты объединяются в создать ответ на всю проблему. Наконец, объективное программирование имитирует реальный мир, создавая внутри компьютера мини-мир со многими объектами, каждый из которых имеет (несколько) уникальные характеристики и взаимодействует с другими. Из этих взаимодействий получится результат.
Каждый стиль программирования имеет свои преимущества и недостатки. Следовательно, делать что-то вроде «чистого программирования» (то есть чисто процедурного - кстати, никто этого не делает, что довольно странно - или чисто функционально, или чисто объективно) очень сложно, если не невозможно, за исключением некоторых элементарных проблем, особенно предназначен для демонстрации преимущества стиля программирования (поэтому мы называем тех, кто любит чистоту, "weenie": D).
Затем из этих стилей у нас есть языки программирования, которые оптимизированы для некоторых стилей. Например, Ассамблея все о процедурных. Хорошо, большинство ранних языков являются процедурными, а не только Asm, как C, Pascal (и Fortran, я слышал). Затем у нас есть все известные Java в целевой школе (на самом деле, Java и C # также находятся в классе, называемом «ориентированным на деньги», но это предмет для другого обсуждения). Также целью является Smalltalk. В функциональной школе у нас были бы «почти функциональные» (некоторые считали их нечистыми) семейства Lisp и ML, а также многие «чисто функциональные» Haskell, Erlang и т. Д. Кстати, есть много общих языков, таких как Perl, Python , Рубин.
источник
Чтобы расширить комментарий Конрада:
Из-за этого функциональный код обычно легче распараллелить. Поскольку (как правило) побочные эффекты функций отсутствуют, и они (в основном) просто действуют на свои аргументы, многие проблемы параллелизма исчезают.
Функциональное программирование также используется, когда вам нужно убедиться, что ваш код верен. Это намного сложнее сделать с процедурным программированием (не просто с функциональным, но все же проще).
Отказ от ответственности: я не использовал функциональное программирование в течение многих лет, и только недавно начал смотреть на него снова, поэтому я могу быть не совсем прав здесь. :)
источник
Одна вещь, которую я не видел, действительно подчеркивалась здесь, это то, что современные функциональные языки, такие как Haskell, действительно больше относятся к функциям первого класса для управления потоком, чем к явной рекурсии. Вам не нужно определять факториал рекурсивно в Haskell, как это было сделано выше. Я думаю что-то вроде
это совершенно идиоматическая конструкция, и по духу она гораздо ближе к использованию цикла, чем к явной рекурсии.
источник
Функциональное программирование идентично процедурному программированию, в котором глобальные переменные не используются.
источник
Процедурные языки имеют тенденцию отслеживать состояние (используя переменные) и имеют тенденцию выполняться как последовательность шагов. Чисто функциональные языки не отслеживают состояние, используют неизменяемые значения и имеют тенденцию исполняться в виде ряда зависимостей. Во многих случаях состояние стека вызовов будет содержать информацию, которая будет эквивалентна той, которая будет храниться в переменных состояния в процедурном коде.
Рекурсия - классический пример программирования функционального стиля.
источник
Конрад сказал:
Порядок оценки в чисто функциональной программе может быть трудно (э-э) рассуждать (особенно с ленью) или даже неважно, но я думаю, что высказывание о том, что оно не очень хорошо определено, звучит так, как будто вы не можете определить, работает ли ваша программа. работать на всех!
Возможно, лучшим объяснением было бы то, что поток управления в функциональных программах основан на том, когда необходимо значение аргументов функции. Хорошая новость в том, что в хорошо написанных программах состояние становится явным: каждая функция перечисляет свои входные данные в качестве параметров, а не произвольно манипулирует глобальным состоянием. Таким образом, на некотором уровне легче рассуждать о порядке оценки по одной функции за раз . Каждая функция может игнорировать остальную часть вселенной и сосредоточиться на том, что ей нужно делать. При объединении функции гарантированно работают так же [1], как и в изоляции.
Решение проблемы ввода в чисто функциональных программах состоит в том, чтобы встроить императивный язык как DSL с использованием достаточно мощной абстракции . В императивных (или не чисто функциональных) языках это не нужно, потому что вы можете «обманывать» и неявно передавать состояние, а порядок вычисления является явным (нравится вам это или нет). Из-за этого «обмана» и принудительной оценки всех параметров для каждой функции в императивных языках 1) вы теряете возможность создавать свои собственные механизмы управления потоками (без макросов), 2) код не является поточно-ориентированным и / или распараллеливаемым по умолчанию, 3) и реализация чего-то вроде отмены (путешествия во времени) требует тщательной работы (императивный программист должен хранить рецепт для возврата старых значений!), Тогда как чистое функциональное программирование покупает вам все эти вещи - и еще несколько, я могу забыли - «бесплатно».
Надеюсь, это не похоже на фанатизм, я просто хотел добавить немного перспективы. Императивное программирование и особенно программирование со смешанной парадигмой в таких мощных языках, как C # 3.0, по-прежнему являются полностью эффективными способами добиться цели, и серебряной пули не существует .
[1] ... за исключением, возможно, относительно использования памяти (см. Foldl и foldl 'в Haskell).
источник
Чтобы расширить комментарий Конрада:
Некоторые функциональные языки имеют то, что называется Lazy Evaluation. Это означает, что функция не выполняется, пока значение не требуется. До этого момента сама функция - это то, что передается.
Процедурные языки - это шаг 1, шаг 2, шаг 3 ... если на шаге 2 вы скажете добавить 2 + 2, тогда это будет сделано правильно. В ленивой оценке вы сказали бы добавить 2 + 2, но если результат никогда не используется, он никогда не делает сложения.
источник
Если у вас есть шанс, я бы порекомендовал получить копию Lisp / Scheme и выполнить в ней несколько проектов. Большинство идей, которые в последнее время стали популярными, были выражены в Лиспе десятилетия назад: функциональное программирование, продолжения (как замыкания), сборка мусора, даже XML.
Так что это был бы хороший способ получить представление о всех этих текущих идеях, а также о некоторых других, таких как символические вычисления.
Вы должны знать, для чего полезно функциональное программирование, а для чего - нет. Это не хорошо для всего. Некоторые проблемы лучше всего выражаются в виде побочных эффектов, когда один и тот же вопрос дает разные ответы в зависимости от того, когда его задают.
источник
@Creighton:
В Haskell есть библиотечная функция под названием product :
или просто:
так что "идиоматический" факториал
будет просто
источник
Процедурное программирование делит последовательности операторов и условных конструкций на отдельные блоки, называемые процедурами, которые параметризуются по аргументам, которые являются (нефункциональными) значениями.
Функциональное программирование такое же, за исключением того, что функции являются первоклассными значениями, поэтому они могут передаваться в качестве аргументов другим функциям и возвращаться как результаты вызовов функций.
Обратите внимание, что функциональное программирование является обобщением процедурного программирования в этой интерпретации. Тем не менее, меньшинство интерпретирует «функциональное программирование» как означающее отсутствие побочных эффектов, что совершенно иное, но не имеет значения для всех основных функциональных языков, кроме Haskell.
источник
Чтобы понять разницу, нужно понять, что парадигма «крестного отца» как процедурного, так и функционального программирования является императивным программированием. .
По сути, процедурное программирование - это просто способ структурирования императивных программ, в котором основным методом абстракции является «процедура». (или «функция» в некоторых языках программирования). Даже объектно-ориентированное программирование - это просто еще один способ структурирования императивной программы, где состояние инкапсулируется в объекты, превращаясь в объект с «текущим состоянием», плюс этот объект имеет набор функций, методов и других вещей, которые позволяют вам программист манипулирует или обновляет состояние.
Теперь, что касается функционального программирования, суть его подхода заключается в том, что он определяет, какие значения принимать и как эти значения следует передавать. (таким образом, нет состояния и изменяемых данных, поскольку он принимает функции в качестве значений первого класса и передает их в качестве параметров другим функциям).
PS: понимание каждой используемой парадигмы программирования должно прояснить различия между ними.
PSS: В конце концов, парадигмы программирования - это просто разные подходы к решению проблем.
PSS: у этого корального ответа есть отличное объяснение.
источник
Ни один из ответов здесь не показывает идиоматическое функциональное программирование. Рекурсивный факторный ответ отлично подходит для представления рекурсии в FP, но большая часть кода не является рекурсивной, поэтому я не думаю, что ответ является полностью репрезентативным.
Скажем, у вас есть массивы строк, и каждая строка представляет целое число, например, «5» или «-200». Вы хотите проверить этот входной массив строк в соответствии с вашим внутренним контрольным примером (используя целочисленное сравнение). Оба решения показаны ниже
процедурный
функциональная
В то время как чисто функциональные языки обычно являются исследовательскими языками (поскольку реальный мир любит бесплатные побочные эффекты), в реальных процедурных языках будет использоваться гораздо более простой функциональный синтаксис, когда это необходимо.
Обычно это реализуется с помощью внешней библиотеки, такой как Lodash , или доступной встроенной в более новые языки, такие как Rust . Тяжелая атлетика функционального программирования осуществляется с помощью функций / понятий , как
map
,filter
,reduce
,currying
,partial
, последние три из которых вы можете посмотреть для дальнейшего понимания.добавление
Для использования в дикой природе компилятору обычно приходится придумывать, как внутренне преобразовать функциональную версию в процедурную, так как накладные расходы на вызов функции слишком велики. Рекурсивные случаи, такие как показанный факториал, будут использовать трюки, такие как хвостовой вызов, для удаления использования памяти O (n). Отсутствие побочных эффектов позволяет функциональным компиляторам реализовывать
&& ret
оптимизацию даже тогда, когда.reduce
это делается в последний раз. Использование Lodash в JS, очевидно, не допускает какой-либо оптимизации, поэтому это удар по производительности (что обычно не касается веб-разработки). Такие языки, как Rust, будут внутренне оптимизированы (и будут иметь такие функции, какtry_fold
помощь в&& ret
оптимизации).источник