Отличительные черты функциональных языков

Примеры имеют очень разные результаты.

Перед рассмотрением различий следует отметить следующее:

  • Прототип конструктора обеспечивает способ совместного использования методов и значений между экземплярами через личное свойство [[Prototype]] экземпляра.
  • Функция функции задана тем, как функция вызывается или с помощью bind (не обсуждается здесь). Если функция вызывается для объекта (например, myObj.method()), то этот внутри метода ссылается на объект. Где этот не задан вызовом или с помощью bind , он по умолчанию ссылается на глобальный объект (окно в браузере) или в строгом режиме, остается неопределенным.
  • JavaScript - это объектно-ориентированный язык, то есть все объекты, включая функции.

Итак, вот фрагменты, о которых идет речь:

var A = function () {
    this.x = function () {
        //do something
    };
};

В этом случае переменной A присваивается значение, которое является ссылкой на функцию. Когда эта функция вызывается с помощью A(), функция этой функции не задается вызовом, поэтому по умолчанию используется глобальный объект, и выражение this.x эффективно window.x. В результате ссылка на выражение функции с правой стороны назначается window.x.

В случае:

var A = function () { };
A.prototype.x = function () {
    //do something
};

происходит нечто совсем другое. В первой строке переменной A присваивается ссылка на функцию. В JavaScript все объекты функций имеют свойство prototype по умолчанию, поэтому нет никакого отдельного кода для создания объекта A.prototype .

Во втором line, A.prototype.x назначается ссылка на функцию. Это создаст свойство x , если оно не существует, или назначьте новое значение, если это произойдет. Таким образом, разница с первым примером заключается в том, какое свойство объекта x участвует в выражении.

Другой пример приведен ниже. Это похоже на первое (и может быть то, о чем вы хотели спросить):

var A = new function () {
    this.x = function () {
        //do something
    };
};

В этом примере оператор new был добавлен перед выражением функции, чтобы вызвать функцию как конструктор. При вызове с new функция этой функции установлена ​​для ссылки на новый объект, чье личное свойство [[Prototype]] установлено для ссылки на общедоступный прототип конструктора . Поэтому в операторе присваивания свойство x будет создано на этом новом объекте. Когда вызывается как конструктор, функция по умолчанию возвращает свой этот объект , поэтому нет необходимости в отдельном заявлении return this;.

Чтобы проверить, что A имеет свойство x :

console.log(A.x) // function () {
                 //   //do something
                 // };

Это необычное использование new , так как единственный способ ссылки на конструктор - через A.constructor . Это было бы гораздо чаще:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

Другой способ достижения аналогичного результата - использовать сразу вызываемое выражение функции:

var A = (function () {
    this.x = function () {
        //do something
    };
}());

В этом случае A присвоено возвращаемое значение вызова функции с правой стороны. Здесь опять же, поскольку этот не задан в вызове, он будет ссылаться на глобальный объект, а this.x - эффективно window.x. Поскольку функция ничего не возвращает, A будет иметь значение undefined.

Эти различия между этими двумя подходами также проявляются, если вы сериализуете и де-сериализуете свои объекты Javascript в / от JSON. Методы, определенные на прототипе объекта, не сериализуются при сериализации объекта, что может быть удобно, если, например, вы хотите сериализовать только части данных объекта, но не его методы:

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

Связанные Вопросы:

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

JavaScript не является языком низкого уровня. Возможно, не очень важно думать о прототипировании или других шаблонах наследования как способ явного изменения способа выделения памяти.

19
задан Norman Ramsey 30 January 2009 в 03:02
поделиться

7 ответов

Первое, что пришло на ум:

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

26
ответ дан 30 November 2019 в 02:13
поделиться

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

  1. С динамическим контролем типов по сравнению со статической, полиморфной системой типов с алгебраическими типами данных и выводом типа. Статическая система типов ограничивает код несколько, но имеет много преимуществ:
    • Типы являются документацией, которая проверяется компилятором.
    • система типов помогает Вам выбрать, какой код записать затем, и когда Вы не уверены, что записать, система типов помогает Вам легко, и быстро исключите много альтернатив.
    • А мощная, современная, полиморфная система типов необоснованно хороша в обнаружении маленького, глупого, ошибки бесполезной траты времени.
  2. Отложенные вычисления как значение по умолчанию везде по сравнению с отложенными вычислениями, ограниченными тщательно управляемыми конструкциями.
    • Ленивый по сравнению с нетерпеливым имеет огромные последствия для Вашей способности предсказать и понять затраты времени и пространства на Ваши программы.
    • На полностью ленивом языке, можно полностью разъединиться производство из данных из решений о том, что сделать с данными, однажды произведенными. Это особенно важно для поисковых проблем, поскольку становится намного легче построить из модулей и снова использовать код.
5
ответ дан 30 November 2019 в 02:13
поделиться

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

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

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

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

3
ответ дан 30 November 2019 в 02:13
поделиться

Мне нравится ответ Chris Conway, который указывает некоторые важные оси, что справка классифицирует различные функциональные языки.

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

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

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

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

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

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

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

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

14
ответ дан 30 November 2019 в 02:13
поделиться

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

фундаментальные дифференциаторы Clojure:

  1. Это имеет программное обеспечение Транзакционная Система памяти, которая делает общее состояние параллельным программирующий легче

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

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

  4. , структуры данных Clojure реализуют интерфейсы Java, такие как Набор, Список, Карта, Выполнимая и Вызываемая в соответствующих случаях. Строками являются просто Строки Java, Числами являются Целые числа Java, и Удваивается. Это означает, что структуры данных Clojure могут быть переданы непосредственно библиотекам Java без любого образования моста или перевода

2
ответ дан 30 November 2019 в 02:13
поделиться

Фундаментальные свойства?

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

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

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

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

2
ответ дан 30 November 2019 в 02:13
поделиться
  1. Нестрогие и строгие вычисления.

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

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

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

  5. Сопоставление с образцом и руководство деконструкция. SML, OCaml, F #, Haskell, Mathematica и Scheme автоматизировать деконструкцию значения.

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

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

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

  9. Макросы. OCaml, Mathematica, Lisp и Scheme - это расширяемые языки.

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

9
ответ дан 30 November 2019 в 02:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: