Отличительные черты функциональных языков - PullRequest
18 голосов
/ 28 января 2009

Известно, что все функциональные языки имеют некоторые основные свойства, такие как использование функций в качестве основного строительного блока для программ со всеми вытекающими последствиями, такими как использование рекурсии вместо итерации. Тем не менее, существуют некоторые фундаментальные различия. Lisp использует одно представление как для кода Lisp, так и для данных, в то время как ML не имеет стандартного представления кода ML. Эрланг имеет встроенный параллелизм на основе актера. На Хаскеле есть монады. Хаскелл проводит различие в системе статических типов между чистыми и нечистыми функциями; ML не делает.

Каковы отличительные фундаментальные различия между другими функциональными языками (Clojure, F #, Arc, любой другой)? Под фундаментальным я подразумеваю что-то, что влияет на то, как вы развиваетесь на этом языке, и, например, , а не , интегрировано ли оно с какой-то широко распространенной средой выполнения.

Ответы [ 7 ]

25 голосов
/ 28 января 2009

с макушки головы:

  • ленивый против нетерпеливый (иначе не строгий против строгий или вызов -by-need против вызов по значению ): оцениваются ли аргументы функции перед применением функции, или после, или никогда?
  • pure против impure : позволяет ли язык функциям иметь побочные эффекты? У него есть изменяемые ссылки?
  • статический против динамический : проверяет ли язык типы во время компиляции или во время выполнения?
  • алгебраические типы данных : поддерживает ли язык сопоставление с образцом по вариантным типам?
  • метапрограммирование : предоставляет ли язык мощную систему генерации кода?
  • параллелизм и параллелизм : являются ли потоки / процессы первоклассной абстракцией? Позволяет ли язык запускать несколько вычислений одновременно?
  • "экзотические" типы : насколько выразительна система статических типов? GADTs? Зависимые типы? Линейные типы? Система F?

Только первые два элемента действительно уникальны для функциональных языков (т. Е. Почти все императивные языки стремятся и нечисты).

14 голосов
/ 28 января 2009

Мне нравится ответ Криса Конвея, в котором указаны некоторые важные оси, которые помогают классифицировать различные функциональные языки.

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

  • Активные шаблоны : ряд FPL имеют алгебраические типы данных и сопоставление с образцом, но функция F #, называемая «активными образцами», позволяет определять новые шаблоны, которые позволяют использовать синтаксис сопоставления с образцом в произвольных данные.
  • Вычислительные выражения : F # имеет красивый синтаксический сахар для создания монадического кода; хотя система типов не может выражать полиморфизм высшего рода (не абстрагируясь над конструкторами типов), поэтому вы не можете написать код для произвольной монады M, код, который вы можете написать для фиксированной монады, очень крутой, и люди пишут некоторые большие понимания в seq {} или асинхронные {} монады.
  • Цитаты : обычный бит "код в качестве данных для метапрограммирования", хотя F # имеет выразительную систему статических типов и богатый синтаксис, и я не уверен, сколько неисписков может это сделать.

С точки зрения общей классификации, F # равно

  • eager (строгий, вызов по значению; но 'lazy' - это ключевое слово и библиотека, а использование seq / IEnumerable для некоторой лени - обычная стратегия)
  • нечистый (хотя синтаксис смещает вас к стилю по умолчанию)
  • статический (с выводом типа, поэтому F # часто «похож на скриптинг», только с безопасностью типов)

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

  • Интеграция с Visual Studio означает отличный опыт редактирования (например, Intellisense)
  • Интеграция с Visual Studio означает отличный опыт отладки (например, точки останова / точки трассировки, локальные объекты, непосредственное окно, ...)
  • REPL для сценариев или пользовательского интерфейса на лету (командная строка fsi.exe или "F # Interactive", интегрированная в VS)
  • .NET интеграция означает, что для большинства 'X' уже есть библиотека для этого
  • сторонних инструментов, таких как FsLex / FsYacc и интеграция с MSBuild, что упрощает «сборку системы»

(Я думаю, что попытка отделить язык от времени выполнения и инструментов - это в основном академическое упражнение.)

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

9 голосов
/ 06 мая 2009
  1. Не строгие и строгие оценки.

  2. Статическая и динамическая типизация.

  3. Структурная или номинальная статическая типизация. OCaml - единственный язык, который я могу думать о структурной типизации (как в объектах, так и в полиморфных вариантах), который закрывает разрыв с динамикой набрав, удалив необходимость определить много типов (например, вариант типов).

  4. Производные Хиндли-Милнера против других алгоритмов вывода статического типа. SML, OCaml, Haskell и F # используют алгоритмы вывода типов, основанные на Хиндли-Милнере, тогда как Scala имеет только локальный вывод типов (например, C # 3) и требует для компиляции гораздо больше аннотаций (Код на Haskell часто полон аннотаций типов на уровне функций, но большинство из них не нужны и добавляются для документации и помогают компилятору при наличии ошибок).

  5. Сравнение шаблонов с руководством деконструкция. SML, OCaml, F #, Хаскель, Математика и Схема автоматизировать деконструкцию значения.

  6. Типы закрытых сумм и только типы открытых сумм. SML, OCaml, F # и Haskell позволяют определять закрытые / запечатанные алгебраические типы для усиления статической типизации, неявно передавая более конкретные ограничения. OCaml и F # также допускают типы открытых сумм, тогда как SML не допускает, а Haskell требует сложного обходного пути (описанного Олегом Киселевым).

  7. Шаблоны с ограниченным временем. Сопоставление с образцом очень быстрое в SML и (ванильном) OCaml, но имеет неизвестную производительность в F # из-за активных шаблонов и даже неизвестной асимптотической сложности в Mathematica.

  8. Компиляция на лету для нативного код. F #, Lisp и Scheme разрешают код генерироваться, компилироваться и выполняется эффективно во время выполнения.

  9. Макросы. OCaml, Mathematica, Lisp и Схема расширяемых языков.

  10. Стандартизированный и проприетарный. SML, Haskell 2010, Common Lisp и Scheme являются стандартизированными языками, тогда как OCaml, Erlang, F # и Mathematica являются проприетарными.

5 голосов
/ 30 января 2009

Существует много отличий, но только два различия, которые я бы назвал фундаментальными в том смысле, что они имеют большое значение для вашего развития:

  1. Динамически типизированный или статический, полиморфный тип системы с алгебраическими типами данных и выводом типа. Система статических типов несколько ограничивает код, но имеет много преимуществ:
    • Типы - это документация, проверяемая компилятором.
    • Система типов помогает вам выбрать, какой код писать дальше, а когда вы не уверены, что именно писать, система типов помогает вам легко и быстро исключить множество альтернатив.
    • Мощная, современная, полиморфная система типов неоправданно хороша в обнаружении мелких, глупых, тратящих время ошибок.
  2. Ленивая оценка как стандартное значение везде, а ленивая оценка ограничена тщательно контролируемыми конструкциями.
    • Lazy vs eager имеет огромное значение для вашей способности прогнозировать и понимать временные и пространственные затраты ваших программ.
    • На ленивом языке вы можете полностью отделить производство данных от решений о том, что делать с данными после их создания. Это особенно важно для проблем поиска, так как становится намного проще модульно использовать и повторно использовать код.
3 голосов
/ 28 января 2009

Функциональное программирование - это стиль, а не языковая конструкция

Большинство функциональных языков имеют общие принципы:

  • Неизменяемые объекты
  • Замыкания и анонимные функции
  • Универсальные алгоритмы
  • Продолжения

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

2 голосов
/ 28 января 2009

Когда вы произносите код как данные, вы обращаетесь к языку, где код представлен в структуре данных. Это называется Homoiconicity , и это обычно верно только для языков, которые являются диалектами LISP или чем-то близким к нему. Haskell, Erlang и Scala не являются гомоиконическими, Clojure - это.

Основные отличия Clojure:

  1. Имеется система программной транзакционной памяти, которая упрощает параллельное программирование с общим состоянием

  2. Это Лисп, в отличие от Haskell или Erlang, поэтому весь код является данными, что позволяет вам вносить изменения в сам язык во время выполнения через систему макросов

  3. Он работает на JVM, что означает, что у вас есть прямой доступ ко всем библиотекам Java

  4. Структуры данных Clojure реализуют Java-интерфейсы, такие как Collection, List, Map, Runnable и Callable, где это уместно. Строки - это просто строки Java, числа - это целые числа Java и числа типа Double. Это означает, что структуры данных Clojure могут передаваться напрямую в библиотеки Java без каких-либо мостов или трансляций

2 голосов
/ 28 января 2009

Основные свойства?

  • Функциональная чистота (отсутствие побочных эффектов)
  • В связи с вышесказанным, отсутствие состояния.
  • Сопоставление с образцом в функциях

Первое прекрасно, второе - уродливый побочный эффект первого (каламбур).

Реальная компенсация отсутствия состояния - это то, что я считаю самым большим отличием между функциональными языками.

Эти несколько вещей дают много халявы. В большинстве случаев языки справляются с запоминанием.

...