Функциональное программирование просто другое или оно действительно сложнее?

12

Функциональное программирование просто другое или оно действительно сложнее ?

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

Мой вопрос: скажем, проблема сейчас в том, чтобы на верблюде

такой, который qwe_asd_zxc_rty_fgh_vbnстановитсяqweAsdZxcRtyFghVbn

Процессуальный путь это:

  1. разделить его вдоль _
  2. перебрать массив, пропуская первый элемент
  3. для каждой записи мы пишем с заглавной буквы первую букву
  4. объединить результаты вместе

Функциональным способом является:

  1. если не могу найти _возвратinput
  2. разрезать inputпо первому _(так, что мы получим qweи asd_zxc_rty_gfh_cvb)
  3. Прописать первую букву headи заключить, что сf(tail)

Хорошо, если у вас есть функциональный опыт и значительный опыт в процедурном программировании, я хотел бы спросить: вам понадобится больше времени, чтобы выяснить процедурный путь, или вам понадобится больше времени, чтобы выяснить функциональный путь?

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

Pacerier
источник
5
Хм, «процедурный путь» кажется мне совершенно функциональным, если мы используем mapшаг 3 вместо мутирующего цикла. Второй подход - это то, что я бы рассмотрел, только если в стандартной библиотеке нет функции разбиения (в этом случае ее следует сравнить с императивным решением, которое также не использует split).
sepp2k
8
В ваших примерах нет ничего конкретно функционального или процедурного. Мне кажется, что вы пытаетесь экстраполировать ошибочное понимание функционального программирования. Не удивительно, что вы получаете необычные результаты.
Рейн Хенрикс
Я не думаю, что функциональное программирование сложно, оно просто другое. Если у вас нет опыта программирования, его так же легко освоить, но по какой-то причине, когда вы изучаете императивное программирование, функциональное программирование становится трудным.
dan_waterworth
1
Я думаю, что различие между функциональным и процедурным становится спорным, поскольку языки maintstream, такие как JavaScript, C #, Groovy, содержат все больше и больше функциональных возможностей.
user281377
2
Императивное программирование гораздо сложнее и нелогично для тех, кто не имел опыта программирования. Такое выражение x=x+1может взорвать неожиданный мозг. Функциональное программирование естественно, это не более чем чисто и удобные строго математические функции.
SK-logic

Ответы:

12

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

Для новичков часто интуитивно понятно, что нельзя просто изменить стоимость чего-либо.

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

jalf
источник
Джалф, ты один из новичков в программировании и довольно легко его освоил?
Pacerier
Я был где-то посередине. До этого я немного разбирался с C ++ и немного PHP, но этого было недостаточно, чтобы по-настоящему привыкнуть к императивному мышлению. Шаблон был довольно четким, когда вы смотрели на класс в целом. Кроме того, это было почти десять лет назад, так что нет, я не совсем новичок в программировании сегодня;)
jalf
Неизменные переменные? Разве Mathematica не является функциональным языком программирования? переменные в Mathematica, безусловно, изменчивы, нет?
user56834
20

Это просто разные

Когда вы программируете, вы, по сути, переводите то, как вы мыслите, в код, расстояние между вашими мыслями и окончательным решением можно назвать «когнитивным разрывом». Чем больше разрыв, тем сложнее будет вам его преодолеть.

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

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

Функциональное и процедурное в любом случае довольно изменчивое понятие, и они имеют тенденцию перекрываться

Homde
источник
4

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

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

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

Многие языки поддерживают это, но для этого они требуют, чтобы мы указали шаблон как нечто вроде регулярного выражения. Регулярные выражения, тем не менее, представляют собой не что иное, как специализированный язык программирования, а реализация RE является компилятором и / или интерпретатором для этого языка. Результатом компиляции RE в основном является функция, которая выполняется (в специальной виртуальной машине RE), чтобы сопоставить выражение с некоторым вводом.

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

В результате мы можем относительно легко обобщить описанную выше проблему. Однако вместо жесткого кодирования «_» и «верхнего регистра» непосредственно в преобразовании мы можем получить что-то вроде:

s&r(pattern, transform, string) {
    if (!pattern(string))
        return string
    else
        return transform(matched part of string) + s&r(rest of string);
}

Но, в отличие от чего-то, где мы указываем шаблон как RE, мы можем указать шаблон непосредственно как реальную функцию и по-прежнему использовать его, что-то вроде:

my_pattern(string) return beginning(string) == '_';

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

Джерри Гроб
источник
4

Вот полный код в Racket :

;; camelize : string -> string
(define (camelize str)
  (let ([parts (regexp-split #rx"_" str)])
    ;; result of regexp-split is never empty
    (apply string-append
           (first parts)
           (map string-titlecase (rest parts)))))

(camelize "qwe_asd_zxc_rty_fgh_vbn")
;; => "qweAsdZxcRtyFghVbn"

Как функциональный программист с процедурным опытом, я не думаю, что мне понадобится больше времени, чтобы «найти» процедурное решение, но, несомненно, мне потребуется больше времени, чтобы его напечатать.

Кстати, пример ожидаемого результата в исходном сообщении неверен: в конце пропущена буква «h».

Райан Калпеппер
источник
Боже, что указал на это. отредактировано
Pacerier
3

Моя любимая теория заключается в том, что модели программирования легче понять, чем ближе они к реальной работе компьютеров. Указатели трудно понять, пока вы не поймете, что это по сути машинные адреса. Трудно понять рекурсию, пока вы сознательно не пройдете небольшой пример, не увидите кадры стека и не поймете, где хранятся различные значения одной и той же переменной. Это не означает, что программирование на ассемблере проще, чем программирование высокого уровня, но, увидев, как это делается, творит чудеса для ментальной модели, которая является ключом к мастерству - будь то программирование или вообще удобство использования.

Теперь процедурная модель несколько ближе к обычной архитектуре машины: присваивания - записи в память (или регистр). Вызовы процедур на самом деле просто причудливые переходы, на ifсамом деле условный переход и т. Д. Но в Лиспе, например, нет простого низкоуровневого эквивалента лексической привязке или лямбда-выражению. Понимание этого требует, чтобы вы представили совершенно отдельную абстрактную функциональную машину между уровнем языка и физической машиной, потому что, очевидно, большинство людей никогда не заходят так далеко.

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

Килиан Фот
источник
7
По этой логике ассемблер должен быть самым простым из всех языков для изучения :)
Homde
4
Функциональное программирование довольно легко понять, если вы подойдете к нему с правильного направления. Упоминаемая вами «абстрактная функциональная машина» - это просто алгебра . Оценка сделана переписыванием термина; Применение функции выполняется путем подстановки. Программисты учатся решать проблемы, используя те же инструменты, которые они уже видели в годы математических выражений. Если они преследуют CS, у них будет достаточно времени, чтобы встретить стаю черепах; в противном случае они все еще изучили полезные навыки решения проблем и принципы дизайна. Взгляните на Как разрабатывать программы .
Райан Калпеппер
2
@mko Нет, по этой логике фактические байт-коды 011011001001101...будут самым простым языком для изучения!
MarkJ
2
@konrad: RISC ассемблер, пожалуй, самый простой язык для изучения. Знать, как заставить его делать что-то полезное - это совсем другая история ...
Брайан Бетчер,