Ответ 1
Реализации языков функционального программирования используют широкий спектр методов реализации. Отличное введение в реализацию диалекта Scheme (a Lisp) дает следующую книгу: Lisp в малой части Christian Queinnec.
Существует совершенно новая парадигма "функционального программирования", которая требует полного изменения моделей мышления по сравнению с процедурным программированием. Он использует функции более высокого порядка, чистоту, монады и т.д., Которые мы обычно не видим в императивных и объектно-ориентированных языках.
Мой вопрос заключается в том, как реализация этих языков отличается от императивных или объектно-ориентированных языков в отношении, например, управления памятью или внутренних элементов, таких как указатели и т.д.
Существуют функциональные языки, которые работают поверх JVM. Означает ли это, что эти языки внутренне работают как другие языки на JVM?
Реализации языков функционального программирования используют широкий спектр методов реализации. Отличное введение в реализацию диалекта Scheme (a Lisp) дает следующую книгу: Lisp в малой части Christian Queinnec.
Код, полученный из функциональных языков, использует многие функции, которые вы видите в разной степени в нефункциональных языках. Сбор мусора перешел в общее пользование. Оптимизация Tail-call выполнена в GCC и VС++.
Закрытие, однако, является отличительной чертой функционального программирования. Вы не видите одного без другого. Если вы определяете "функциональные языки", чтобы ссылаться только на чистые функциональные языки, эти два не являются синонимами, поскольку вы обнаруживаете замыкания на императивных языках, поддерживающих функциональное программирование (например, Javascript и Scheme (что является технически необходимым, хотя функциональная парадигма - это то, что в основном используемый)). Закрытие может быть реализовано с помощью спагетти-стека для стека вызовов или путем копирования локальных переменных при выходе из фрейма стека или путем выделения локальных переменных на кучу и позволяя сбор мусора заботиться о них.
Как только у вас есть закрытие, анонимные функции относительно просты (с помощью интерпретатора они очень легкие). С компилятором функция преобразуется в байт-код во время компиляции, а байт-код (скорее, адрес точки входа) связан во время выполнения с текущей средой.
Состав функций может основываться на анонимной функции. Когда компилятор встречает оператор компоновки функций f . g
, он создает анонимную функцию, которая вызывает два аргумента f
и g
, передавая результат одного в качестве аргумента другому.
Монады могут быть реализованы на языках OO, они просто не так необходимы, как в чистых функциональных языках. Монеты ввода-вывода не являются чем-то особенным, они просто полагаются на тот факт, что базовая платформа допускает побочные эффекты.
Я предполагаю, что есть много аспектов, которые пользуются особым вниманием в функциональных языках, что приходит на ум:
Функциональные языки часто используют рекурсию. Поэтому любая реализация должна попытаться оптимизировать этот случай. Например. идентифицировать хвостовую рекурсию и преобразовать в цикл внутри (таким образом сохраняя накладные расходы на функции, такие как сохранение/восстановление стека). (http://en.wikipedia.org/wiki/Tail_recursion)
Реализация функционального языка программирования, такого как Haskell, часто очень отличается от реализации императивных языков. Вы можете прочитать об одном из способов сделать это здесь. Несмотря на то, что этой статье несколько лет, я считаю, что идеи все еще используются.
Самое большое различие, которое приходит на ум, состоит в том, что функциональные языки имеют тенденцию быть сконструированы таким образом, чтобы исходный код desugared был математически простым и мощный промежуточный язык. Этот язык обычно содержит лямбда, вызовы функций, если /else, типы машин, что-то вроде let
, а не намного больше. Преобразованный код является глубоко вложенным, многословным и нереалистичным для человека. Синтаксис поверхности отбрасывается.
Компилятор для такого языка должен сделать некоторую вставку и несколько оптимизаций закрытия для создания достойного кода. (Для меня эта оптимизация закрытия баз данных кажется нетривиальной - анализ побега и т.д. - но это может быть просто отсутствие знакомства.)
Все работает на одном процессоре (и, следовательно, на одних и тех же инструкциях по сборке), так что пока вы углубляетесь достаточно, все то же самое внутри.
@outis: хотя язык может их поддерживать, закрытие конфликтует с математической концепцией функции так же, как и побочные эффекты: они позволяют получать разные результаты по тем же аргументам. Это делает процедуры процедурными, а не функциональными.
Тем не менее, есть аргументы эффективности, которые способствуют закрытию глобальных переменных (особенно в контексте реализации компилятора). [Но я знаю о функциональных языках, которые не обеспечивают закрытие напрямую, даже если "работать alikes" можно реализовать.]
(Тем не менее, currying похож на замыкания и не страдает от этого конфликта и действительно регулярно присутствует в функциональных языках.)
В любом случае, на мой взгляд, языки функционального программирования - это языки, которые прилагают большие усилия, чтобы сделать вычисление представимым, как если бы они были математическими функциями. Это означает, что оптимизация наклонена при оптимизации функций.
Гипотетически, по крайней мере, функциональные языки позволяют машине работать на более глубоких абстракциях, чем было бы полезно для чисто процедурного подхода.