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

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

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

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

  • В вашем коде используется цикл for, который является процедурным. Для элегантности вы должны писать функционально.
  • Ваш код имеет побочные эффекты, что является грязным. Для чистоты вы должны обернуть IO в монаду.
  • В вашем коде используется объектно-ориентированный класс. Чтобы не иметь состояния, вы должны писать функции более высокого порядка.

Есть ли разница между этой грубой логикой и [Родители для вас] и [Женщины не подходят для программирования]? Многие из этих безответственных высказываний создали в нынешнем сообществе стереотипы об объектно-ориентированном и императивном программировании. На самом деле, идея противопоставления функционального программирования объектно-ориентированному/императивному программированию по своей сути слаба в своей категоризации. Если оставить это в стороне, эти аргументы также весьма произвольны, игнорируя сценарии применения технологии.

Например, одним из главных достоинств функционального программирования является то, что чистые функции не имеют состояния. Мы слишком много слышали о его преимуществах: предсказуемые результаты, хорошо для тестирования, хорошо для повторного использования, хорошо для параллелизма... Все звучит настолько идеально, что мы можем написать полную систему? Абсурд здесь в том, чтоЧем ближе вы подходите к оригинальному внешнему виду компьютера под капотом, тем дальше вы уходите от чисто функционального и не имеющего состояния.

Когда вы попытаетесь понять настоящие основы процессора/графики/сети и т. д., вы обнаружите, что они вообще не работают:

  • ЦП сам по себе является наиболее типичным конечным автоматом. Например, авторские игрушки выходного дняСимулятор ЧИП-8В нем состояние процессора — это просто набор регистров, указателей стека и счетчиков, моделируемых несколькими переменными. Каждая инструкция — это просто функция, которая изменяет глобальное состояние, что, конечно, не является чистым, но соответствует интуиции и абстракции того, как работает ЦП.
  • API-интерфейсы, которые управляют работой видеокарт, ужасно отслеживают состояние. Я считаю, что любой студент, который пытался построить конвейер рендеринга WebGL с нуля, может понять, что это значит. А в API-интерфейсе драйвера дисплея следующего поколения, который выжимает максимальную производительность, состояние, требующее обслуживания человеком, будет еще более тривиальным.
  • Как мигрировать конечный автомат стека сетевых протоколов бесчисленное количество раз рисовалось в учебнике «Компьютерная сеть». Даже на самой дурацкой веб-странице, инкапсулированной на прикладном уровне, посмотрите на выполнение предложения в консолиperformance.timingНелегко правильно нарисовать отношения перехода состояний между этими полями.

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

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

       JMP LOOP   ; 首先跳到底部以开始循环
BEGIN: NOP        ; 空指令占位符
                  ; ...此处开始放置循环体中代码
                  ; ...
                  ; ...
                  ; ...执行完循环体内代码
LOOP:  CMP ...    ; 检查条件
       JNE BEGIN  ; 若不满足则跳转到 BEGIN 位置

Для цикла for, который подвергся критике со стороны функциональных энтузиастов, необходимо только добавить процедуры инициализации и временные переменные счетчика к потоку управления выше. А устаревшие синтаксис break и continue нужно только добавить больше меток, чтобы гибко основываться на них.JMPвыполнить. По сравнению с последовательностью логики перехода, которая требует тщательного сохранения и восстановления контекста при вызове и возврате функции, синтаксис императивного цикла, очевидно, проще реализовать — конечно, можно сказать, что функциональный язык, такой как Scheme, который интерпретатор легче реализовать, и я реализовал диалект Scheme как игрушку на выходных.о, языкустный переводчик. Но сколько инженерной практической ценности в этом языке, который почти эквивалентен рукописному синтаксическому дереву? Подобные места отражаются и в абстракции различных математических вычислений. Как автор способствовал пиаруgl-matrixБиблиотека для матричных операций, в которой много мутаций тоже очень нефункциональна, но на самом деле все равно довольно аккуратная, надежная и эффективная.

Некоторых энтузиастов функционального программирования также немного озадачивает восхищение всеми функциональными методами, такими как рекурсия: написанный вами цикл for слишком низкоуровневый, посмотрите на мою элегантную хвостовую рекурсию и его собственную оптимизацию интерпретатора. взорваться! Конечно, использование рекурсии довольно лаконично и удобно для чтения при работе с вложенными структурами данных. У автора был такой опыт, когда он пытался реализовать домашнюю работу по рекурсивному спуску и анализатору LALR перед выпуском: нерекурсивное написание в настоящее время действительно многословно. Однако этот подход, который должен улучшить читаемость за счет снижения производительности, часто ошибочно воспринимается как хорошая реализация и используется неправильно. Например, алгоритм глубокого копирования легко реализовать с помощью рекурсии, но объективно возникает риск переполнения стека. В качестве решения мы можем реализовать это, имитируя стек с массивом. Тогда ваш код менее функционален: вы бы отказались исправлять ошибки переполнения стека, потому что функциональный код более элегантный?

Подобный отказ также отражается в восхищении некоторыми концепциями, которые на самом деле более неясны. Многие новички, желающие начать работу с функциональным программированием, будут введены в заблуждение концепцией монад [моноидов на самофункторах]. Это правда, что вы можете интерпретировать простые и легкие в использовании концепции хуков и промисов как монады.Автор написал статью с точки зрения единичного элемента и ассоциативности, чтобы доказатьПочему обещание является монадой. Однако то, что является очень практичным и простым для понимания в реальной разработке, должно быть формально определено и объяснено с использованием более непонятного набора понятий, что, вероятно, не способствует популяризации превосходных инструментов и понятий. Например, понятие функции на японском языке называется Guanshu.Если вы не понимаете это слово в японской системе, это не влияет на самосогласованность системы знаний китайского пользователя и использование функций. Более того, монада фактически эквивалентна [паттерну проектирования] в парадигме функционального программирования.Разве отказ от шаблонов проектирования не является одним из преимуществ самого функционального программирования?

Когда дело доходит до шаблонов проектирования, нельзя обойтись без разработки программного обеспечения. В настоящее время у нас есть много принципов проектирования на уровне [Дао], но эти принципы, которые действительно полезны для инженерного масштабирования, имеют мало общего с конкретными парадигмами программирования. Например, все мы знаем, что модульное разделение с высокой связностью и низкой связанностью способствует сопровождению, но наиболее важную роль в этом измерении играют не функциональные грамматические особенности, а диспетчер пакетов языка, спецификации загрузки модулей и т. д. . Другой пример — изменение архитектуры ECS игровой индустрии, эволюция которой в направлении «комбинация лучше наследования» все еще может быть реализована в объектно-ориентированных языках. Даже в реальных технических случаях самая крупная и надежная реализация внешнего интерфейса, которая тесно связана с пользовательским интерфейсом, по-прежнему очень объектно-ориентирована — среды пользовательского интерфейса рабочего стола Windows и macOS не являются производными от функциональных языков, не Будет ли диспетчер рабочего стола ОС управлять глобальным состоянием в одном хранилище, как это делает Redux?

Пока Tucao эта статья подошла к концу. Но надо явно не париться при написании, автору более чем твердого порошка императивного программирования (Наоборот, я же специально написалRxJS имитирует планирование лифтастатью Амвэй). Пришло время сделать несколько уточнений и обращений:

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

В реальном кодировании автор уделяет больше внимания [интуитивности]. Это примерно включает два измерения:

  • Используется ли языковая функция в соответствии со сценарием, для решения которого она была разработана.
  • Соответствует ли реализация конкретного требования самой простой и прямой абстракции.

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