Неизменяемость или изменчивость не являются концепциями, которые имеют смысл в функциональном программировании.
Вычислительный контекст
Это очень хороший вопрос, который представляет собой интересное продолжение (а не дубликат) другого недавнего вопроса: в чем разница между присвоением, оценкой и привязкой имени?
Вместо того, чтобы отвечать на ваши заявления по одному, я пытаюсь здесь дать вам структурированный обзор того, что находится в ставках.
Есть несколько вопросов, которые нужно рассмотреть, чтобы ответить вам, в том числе:
Что такое модель вычислений и какие концепции имеют смысл для данной модели
Каково значение слов, которые вы используете, и как это зависит от контекста
Стиль функционального программирования кажется глупым, потому что вы видите его императивным взглядом программиста. Но это другая парадигма, и ваши императивные концепции и восприятие чужды, неуместны. Компиляторы не имеют таких предрассудков.
Но конечный вывод состоит в том, что можно писать программы чисто функциональным способом, в том числе для машинного обучения, в то время как в функциональном программировании нет концепции хранения данных. Я, кажется, не согласен по этому вопросу с другими ответами.
В надежде, что некоторые будут заинтересованы, несмотря на длину этого ответа.
Вычислительные парадигмы
Речь идет о функциональном программировании (также называемом аппликативным программированием), конкретной модели вычислений, теоретическим и простейшим представителем которой является лямбда-исчисление.
Если вы остаетесь на теоретическом уровне, есть много моделей вычислений: машина Тьюринга (TM), машина RAM и другие , лямбда-исчисление, комбинаторная логика, теория рекурсивных функций, системы полуэти и т. Д. Более мощные вычислительные системы модели оказались эквивалентными с точки зрения того, к чему они могут обратиться, и в этом суть
тезиса Черча-Тьюринга .
Важной концепцией является приведение моделей друг к другу, что является основой для установления эквивалентностей, которые приводят к тезису Черча-Тьюринга. С точки зрения программистов, приведение одной модели к другой - это почти то, что обычно называют компилятором. Если вы берете логическое программирование в качестве своей модели вычислений, оно весьма отличается от модели, предоставленной ПК, который вы купили в магазине, и компилятор переводит программы, написанные на языке логического программирования, в вычислительную модель, представленную вашим ПК (в значительной степени оперативная память компьютера).
β
На практике, языки программирования, которые мы используем, имеют тенденцию смешивать понятия различного теоретического происхождения, пытаясь сделать это так, чтобы выбранные части программы могли извлечь выгоду из свойств некоторой модели, где это уместно. Аналогично, люди, строящие системы, могут выбирать разные языки для разных компонентов, чтобы лучше всего соответствовать языку для поставленной задачи.
Следовательно, вы редко видите парадигму программирования в чистом виде на языке программирования. Языки программирования по-прежнему классифицируются в соответствии с доминирующей парадигмой, но свойства языка могут быть затронуты, когда задействованы концепции из других парадигм, часто размывая различия и концептуальные проблемы.
Как правило, такие языки, как Haskell и ML или CAML, считаются функциональными, но они допускают императивное поведение ... Иначе зачем говорить о « чисто функциональном подмножестве »?
Тогда можно утверждать, что вы можете делать то или иное на моем функциональном языке программирования, но на самом деле он не отвечает на вопрос о функциональном программировании, когда полагается на то, что можно считать экстрафункциональным.
Ответы должны быть более точно связаны с конкретной парадигмой, без дополнительных дополнений.
Что такое переменная?
Другая проблема - использование терминологии. В математике переменная - это сущность, которая обозначает неопределенное значение в некоторой области. Используется для различных целей. Используемый в уравнении, он может обозначать любое значение, такое, что уравнение проверяется. Это видение используется в логическом программировании под названием « логическая переменная », вероятно, потому, что переменная имени уже имела другое значение при разработке логического программирования.
В традиционном императивном программировании под переменной понимается некоторый контейнер (или область памяти), который может запомнить представление значения и, возможно, заменить его текущее значение другим).
В функциональном программировании переменная имеет то же назначение, что и в математике, в качестве заполнителя для некоторого значения, которое еще предстоит предоставить. В традиционном императивном программировании эту роль фактически играет константа (ее не следует путать с литералами, для которых определенное значение выражается с помощью обозначения, характерного для этой области значений, например 123, true, ["abdcz", 3.14]).
Переменные любого вида, а также константы могут быть представлены идентификаторами.
Императивная переменная может изменить свое значение, и это является основой изменчивости. Функциональная переменная не может.
Языки программирования обычно позволяют создавать более крупные сущности из более мелких в языке.
Императивные языки позволяют таким конструкциям включать переменные, и это то, что дает вам изменяемые данные.
Как читать программу
Программа по сути представляет собой абстрактное описание вашего алгоритма - это какой-то язык, будь то прагматический дизайн или парадигматически чистый язык.
В принципе, вы можете принять каждое утверждение за то, что оно должно означать абстрактно. Затем компилятор переведет это в некоторую подходящую форму для компьютера, чтобы выполнить, но это не ваша проблема в первом приближении.
Конечно, реальность немного жестче, и часто полезно иметь некоторое представление о том, что происходит, чтобы избежать структур, с которыми компилятор не будет знать, как иметь дело с эффективным исполнением. Но это уже оптимизация ... для которой компиляторы могут быть очень хорошими, часто лучше, чем программисты.
Функциональное программирование и изменчивость
Изменчивость основана на существовании императивных переменных, которые могут содержать значения, которые должны быть изменены при присваивании. Так как они не существуют в функциональном программировании, все может рассматриваться как неизменное.
Функциональное программирование имеет дело исключительно с ценностями.
Ваши первые четыре утверждения об неизменности в основном верны, но опишите с настоятельной точки зрения то, что не обязательно. Это немного похоже на описание красками в мире, где все слепы. Вы используете понятия, которые чужды функциональному программированию.
У вас есть только чистые значения, а массив целых чисел является чистым значением. Чтобы получить другой массив, который отличается только одним элементом, вы должны использовать другое значение массива. Изменение элемента - это просто концепция, которая не существует в этом контексте. У вас может быть функция, которая имеет массив и несколько индексов в качестве аргумента и возвращает результат, который является почти идентичным массивом, который отличается только в том случае, если это указано индексами. Но это все еще независимое значение массива. Как эти ценности представлены не ваша проблема. Может быть, они «разделяют» многое в императивном переводе для компьютера ... но это работа компилятора ... и вы даже не хотите знать, для какой архитектуры машины он компилируется.
Вы не копируете значения (это не имеет смысла, это чуждое понятие). Вы просто используете значения, которые существуют в доменах, которые вы определили в вашей программе. Либо вы описываете их (как литералы), либо они являются результатом применения функции к некоторым другим значениям. Вы можете дать им имя (определяя таким образом константу), чтобы убедиться, что одно и то же значение используется в разных местах программы. Обратите внимание, что приложение функции должно восприниматься не как вычисление, а как результат применения к заданным аргументам. Письмо 5+2
или письмо 7
равняется тому же самому. Что согласуется с предыдущим пунктом.
Здесь нет обязательных переменных. Назначение невозможно. Вы можете привязывать имена только к значениям (для формирования констант), в отличие от императивных языков, где вы можете привязывать имена к назначаемым переменным.
Имеет ли это сложную стоимость, совершенно неясно. Прежде всего, вы ссылаетесь на сложность, касающуюся императивных парадигм. Он не определяется как таковой для функционального программирования, если только вы не решите читать свою функциональную программу как императивную, что не является целью разработчика. Действительно, функциональное представление призвано позволить вам не беспокоиться о таких проблемах и сосредоточиться на том, что вычисляется. Это немного похоже на спецификацию и реализацию.
Компилятор должен позаботиться о реализации и быть достаточно умным, чтобы наилучшим образом адаптировать то, что должно быть сделано, к аппаратному обеспечению, которое будет это делать, что бы это ни было.
Я не говорю, что программисты никогда не беспокоятся об этом. Я также не говорю, что языки программирования и технологии компиляции настолько развиты, насколько нам этого хотелось бы.
Отвечая на вопросы
Вы не изменяете существующее значение (инопланетное понятие), но вычисляете новые значения, которые отличаются там, где это необходимо, возможно, имея один дополнительный элемент - это список.
Программа может получить новые данные. Все дело в том, как вы выражаете это на языке. Например, вы можете считать, что программа работает с одним конкретным значением, возможно неограниченным по размеру, которое называется входным потоком. Это значение, которое должно находиться там (независимо от того, известно ли оно вам полностью или нет, это не ваша проблема). Затем у вас есть функция, которая возвращает пару, состоящую из первого элемента потока и остальной части потока.
Вы можете использовать это для построения сетей взаимодействующих компонентов чисто прикладным способом (сопрограммы)
Машинное обучение - это еще одна проблема, когда вам нужно накапливать данные и изменять значения. В функциональном программировании вы этого не делаете: вы просто вычисляете новые значения, которые соответствующим образом различаются в зависимости от данных обучения. Получившаяся машина тоже будет работать. Что вас беспокоит, так это вычислительная эффективность времени и пространства. Но, опять же, это другая проблема, которая в идеале должна решаться компилятором.
Заключительные замечания
Из комментариев и других ответов совершенно ясно, что практические языки функционального программирования не являются чисто функциональными. Это отражает тот факт, что наша технология все еще нуждается в совершенствовании, особенно в том, что касается компиляции.
Можно ли писать в чисто аппликативном стиле? Ответ был известен около 40 лет, и это «да». Самой целью денотационной семантики в том виде, в каком она появилась в 1970-х годах, было именно то, чтобы перевести (скомпилировать) языки в чисто функциональный стиль, который считался лучше понятным математически и, таким образом, считался лучшим средством для определения семантики программ.
Интересный аспект заключается в том, что императивную структуру программирования, включая переменные, можно преобразовать в функциональный стиль путем введения соответствующих областей значений, таких как хранилище данных. И несмотря на функциональный стиль, он остается удивительно похожим на код реальных компиляторов, написанных в императивном стиле.