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

Основные принципы программирования: функциональное программирование

Основные принципы программирования: функциональное программирование

Если вы такой же разработчик, как и я, то наверняка сперва изучали парадигму ООП. Первым вашим яыком были Java или C++ — или, если вам повезло, Ruby, Python или C# — поэтому вы наверняка знаете, что такое классы, объекты, экземпляры и т.д. В чём вы точно не особо разбираетесь, так это в основах той странной парадигмы, называющейся функциональным программированием, которая существенно отличается не только от ООП, но и от процедурного, прототипно-ориентированного и других видов программирования.

Функциональное программирование становится популярным — и на то есть причины. Сама парадигма не нова: Haskell, пожалуй, является самым функциональным языком, а возник он в 90-ых. Такие языки, как Erlang, Scala, Clojure также попадают под определение функциональных. Одним из основных преимуществ функционального программирования является возможность написания программ, работающих конкурентно (если вы уже забыли, что это — освежите память прочтением статьи о конкурентности), причём без ошибок — то есть взаимные блокировки и потокобезопасность вас не побеспокоят.

У функционального программирования есть много преимуществ, но возможность максимального использования ресурсов процессора благодаря конкурентному поведению — это его главный плюс. Ниже мы рассмотрим основные принципы функционального программирования.

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

1. Все функции — чистые

Это правило безусловно является основным в функциональном программировании. Все функции являются чистыми, если они удовлетворяют двум условиям:

Второе правило — никаких побочных эффектов — является более широким по своей природе. Побочный эффект — это изменение чего-то отличного от функции, которая исполняется в текущий момент. Изменение переменной вне функции, вывод в консоль, вызов исключения, чтение данных из файла — всё это примеры побочных эффектов, которые лишают функцию чистоты. Может показаться, что это серьёзное ограничение, но подумайте ещё раз. Если вы уверены, что вызов функции не изменит ничего «снаружи», то вы можете использовать эту функцию в любом сценарии. Это открывает дорогу конкурентному программированию и многопоточным приложениям.

2. Все функции — первого класса и высшего порядка

Эта концепция — не особенность ФП (она используется в Javascript, PHP и других языках) — но его обязательное требование. На самом деле, на Википедии есть целая статья, посвящённая функциям первого класса. Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной. Это позволяет управлять функцией как обычным типом данных и в то же время исполнять её.

Функции высшего порядка же определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию. Типичными примерами таких функций являются map и filter.

3. Переменные неизменяемы

Тут всё просто. В функциональном программировании вы не можете изменить переменную после её инициализации. Вы можете создавать новые, но не можете изменять существующие — и благодаря этому вы можете быть уверены, что никакая переменная не изменится.

4. Относительная прозрачность функций

Сложно дать корректное определение относительной прозрачности. Самым точным я считаю такое: если вы можете заменить вызов функции на возвращаемое значение, и состояние при этом не изменится, то функция относительно прозрачна. Это, быть может, очевидно, но я приведу пример.

Пусть у нас есть Java-функция, которая складывает 3 и 5:

Очевидно, что любой вызов этой функции можно заменить на 8 — значит, функция относительно прозрачна. Вот пример непрозрачной функции:

Эта функция ничего не возвращает, но печатает текст, и при замене вызова функции на ничто состояние консоли будет другим — значит, функция не является относительно прозрачной.

5. Функциональное программирование основано на лямбда-исчислении

Функциональное программирование сильно опирается на математическую систему, называющуюся лямбда-исчислением. Я не математик, поэтому я не буду углубляться в детали — но я хочу обратить внимание на два ключевых принципа лямбда-исчисления, которые формируют самое понятие функционального программирования:

Как я уже говорил, лямбда-исчисление на этом не заканчивается — но мы рассмотрели лишь ключевые аспекты, связанные с ФП. Теперь, в разговоре о функциональном программировании вы сможете блеснуть словечком «лямбда-исчисление», и все подумают, что вы шарите 🙂

Заключение

Функциональное программирование серьёзно напрягает мозги — но это очень мощный подход, и я считаю, что его популярность будет только расти.

Если вы хотите узнать о функциональном программировании побольше, то советуем вам ознакомиться с примерами использования принципов ФП в JavaScript (часть 1, часть 2), а также с циклом статей, посвящённым функциональному C#.

Источник

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

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

🤔 Функциональное — это про функции?

❌ Нет. Функ­ци­о­наль­ное — это не про функ­ции. Функ­ции есть почти в любых язы­ках про­грам­ми­ро­ва­ния: и в функ­ци­о­наль­ных, и в импе­ра­тив­ных. Отли­чие функ­ци­о­наль­но­го про­грам­ми­ро­ва­ния от импе­ра­тив­но­го — в общем подходе.

Метафора: инструкция или книга правил

Пред­ставь­те, что вы откры­ва­е­те кафе-столовую. Сей­час у вас там два типа сотруд­ни­ков: пова­ра и администраторы.

Для пова­ров вы пише­те чёт­кие поша­го­вые инструк­ции для каж­до­го блю­да. Например:

Повар дол­жен сле­до­вать этим инструк­ци­ям ров­но в той после­до­ва­тель­но­сти, в кото­рой вы их напи­са­ли. Нель­зя сна­ча­ла почи­стить свёк­лу, а потом взять её. Нель­зя посо­лить кастрю­лю, в кото­рой нет воды. Поря­док дей­ствий важен и опре­де­ля­ет­ся вами. Это при­мер импе­ра­тив­но­го про­грам­ми­ро­ва­ния. Вы пове­ле­ва­е­те испол­ни­те­лем. Мож­но ска­зать, что испол­ни­те­ли выпол­ня­ют ваши задания.

Для адми­ни­стра­то­ра вы пише­те не инструк­цию, а как бы кни­гу правил:

Это тоже коман­ды, но испол­нять их адми­ни­стра­тор будет не в этой после­до­ва­тель­но­сти, а в любой на своё усмот­ре­ние. Мож­но ска­зать, что зада­ча это­го чело­ве­ка — испол­нять функ­ции адми­ни­стра­то­ра, и мы опи­са­ли пра­ви­ла, по кото­рым эти функ­ции испол­нять. Это при­мер функ­ци­о­наль­но­го программирования.

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

❌ Про­грам­ми­сты, не бомбите

Конеч­но же, это упро­ще­но для пони­ма­ния. Вы сами попро­буй­те это нор­маль­но объ­яс­нить (мож­но пря­мо в комментах).

Императивное программирование

При­ме­ры язы­ков: C, С++, Go, Pascal, Java, Python, Ruby

Импе­ра­тив­ное про­грам­ми­ро­ва­ние устро­е­но так:

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

Есть пере­мен­ные, кото­рые могут хра­нить дан­ные и изме­нять­ся во вре­мя рабо­ты про­грам­мы. Пере­мен­ная — это ячей­ка для дан­ных. Мы можем создать пере­мен­ную нуж­но­го нам типа, поло­жить туда какое-то зна­че­ние, а потом поме­нять его на другое.

Если под­про­грам­ме на вход подать какое-то зна­че­ние, то резуль­тат будет зави­сеть не толь­ко от исход­ных дан­ных, но и от дру­гих пере­мен­ных. Напри­мер, у нас есть функ­ция, кото­рая воз­вра­ща­ет раз­мер скид­ки при покуп­ке в онлайн-магазине. Мы добав­ля­ем в кор­зи­ну товар сто­и­мо­стью 1000 ₽, а функ­ция долж­на нам вер­нуть раз­мер полу­чив­шей­ся скид­ки. Но если скид­ка зави­сит от дня неде­ли, то функ­ция сна­ча­ла про­ве­рит, какой сего­дня день, потом посмот­рит по таб­ли­це, какая сего­дня скидка.

Полу­ча­ет­ся, что в раз­ные дни функ­ция полу­ча­ет на вход 1000 ₽, но воз­вра­ща­ет раз­ные зна­че­ния — так рабо­та­ет импе­ра­тив­ное про­грам­ми­ро­ва­ние, когда всё зави­сит от дру­гих переменных.

После­до­ва­тель­ность выпол­не­ния под­про­грамм регу­ли­ру­ет­ся про­грам­ми­стом. Он зада­ёт нуж­ные усло­вия, по кото­рым дви­жет­ся про­грам­ма. Вся логи­ка пол­но­стью про­ду­мы­ва­ет­ся про­грам­ми­стом — как он ска­жет, так и будет. Это зна­чит, что раз­ра­бот­чик может точ­но пред­ска­зать, в какой момент какой кусок кода выпол­нит­ся — код полу­ча­ет­ся пред­ска­зу­е­мым, с понят­ной логи­кой работы.

Если у нас код, кото­рый счи­та­ет скид­ку, дол­жен вызы­вать­ся толь­ко при финаль­ном оформ­ле­нии зака­за, то он выпол­нит­ся имен­но в этот момент. Он не посчи­та­ет скид­ку зара­нее и не про­пу­стит момент оформления.

👉 Суть импе­ра­тив­но­го про­грам­ми­ро­ва­ния в том, что про­грам­мист опи­сы­ва­ет чёт­кие шаги, кото­рые долж­ны при­ве­сти код к нуж­ной цели.

Зву­чит логич­но, и боль­шин­ство про­грам­ми­стов при­вык­ли имен­но к тако­му пове­де­нию кода. Но функ­ци­о­наль­ное про­грам­ми­ро­ва­ние рабо­та­ет совер­шен­но иначе.

Функциональное программирование

При­ме­ры язы­ков: Haskell, Lisp, Erlang, Clojure, F#

Смысл функ­ци­о­наль­но­го про­грам­ми­ро­ва­ния в том, что мы зада­ём не после­до­ва­тель­ность нуж­ных нам команд, а опи­сы­ва­ем вза­и­мо­дей­ствие меж­ду ними и под­про­грам­ма­ми. Это похо­же на то, как рабо­та­ют объ­ек­ты в объектно-ориентированном про­грам­ми­ро­ва­нии, толь­ко здесь это реа­ли­зу­ет­ся на уровне всей программы.

Напри­мер, в ООП нуж­но задать объ­ек­ты и пра­ви­ла их вза­и­мо­дей­ствия меж­ду собой, но так­же мож­но и напи­сать про­сто код, кото­рый не при­вя­зан к объ­ек­там. Он как бы сто­ит в сто­роне и вли­я­ет на рабо­ту про­грам­мы в целом — отправ­ля­ет одни объ­ек­ты вза­и­мо­дей­ство­вать с дру­ги­ми, обра­ба­ты­ва­ет какие-то резуль­та­ты и так далее.

Функ­ци­о­наль­ное про­грам­ми­ро­ва­ние здесь идёт ещё даль­ше. В нём весь код — это пра­ви­ла рабо­ты с дан­ны­ми. Вы про­сто зада­ё­те нуж­ные пра­ви­ла, а код сам раз­би­ра­ет­ся, как их применять.

Если мы срав­ним прин­ци­пы функ­ци­о­наль­но­го под­хо­да с импе­ра­тив­ным, то един­ствен­ное, что сов­па­дёт, — и там, и там есть коман­ды, кото­рые язык может выпол­нять. Всё осталь­ное — разное.

Коман­ды мож­но соби­рать в под­про­грам­мы, но их после­до­ва­тель­ность не име­ет зна­че­ния. Нет раз­ни­цы, в каком поряд­ке вы напи­ше­те под­про­грам­мы — это же про­сто пра­ви­ла, а пра­ви­ла при­ме­ня­ют­ся тогда, когда нуж­но, а не когда про них сказали.

Пере­мен­ных нет. Вер­нее, они есть, но не в том виде, к кото­ро­му мы при­вык­ли. В функ­ци­о­наль­ном язы­ке мы можем объ­явить пере­мен­ную толь­ко один раз, и после это­го зна­че­ние пере­мен­ной изме­нить­ся не может. Это как кон­стан­ты — запи­са­ли и всё, теперь мож­но толь­ко про­чи­тать. Сами же про­ме­жу­точ­ные резуль­та­ты хра­нят­ся в функ­ци­ях — обра­тив­шись к нуж­ной, вы все­гда полу­чи­те иско­мый результат.

Функ­ции все­гда воз­вра­ща­ют одно и то же зна­че­ние, если на вход посту­па­ют одни и те же дан­ные. Если в про­шлом при­ме­ре мы отда­ва­ли в функ­цию сум­му в 1000 ₽, а на выхо­де полу­ча­ли скид­ку в зави­си­мо­сти от дня неде­ли, то в функ­ци­о­наль­ном про­грам­ми­ро­ва­нии если функ­ция полу­чит в каче­стве пара­мет­ра 1000 ₽, то она все­гда вер­нёт одну и ту же скид­ку неза­ви­си­мо от дру­гих переменных.

Мож­но про­ве­сти ана­ло­гию с мате­ма­ти­кой и сину­са­ми: синус 90 гра­ду­сов все­гда равен еди­ни­це, в какой бы момент мы его ни посчи­та­ли или какие бы углы у нас ещё ни были в зада­че. То же самое и здесь — всё пред­ска­зу­е­мо и зави­сит толь­ко от вход­ных параметров.

После­до­ва­тель­ность выпол­не­ния под­про­грамм опре­де­ля­ет сам код и ком­пи­ля­тор, а не про­грам­мист. Каж­дая коман­да — это какое-то пра­ви­ло, поэто­му нет раз­ни­цы, когда мы запи­шем это пра­ви­ло, в нача­ле или в кон­це кода. Глав­ное, что­бы у нас это пра­ви­ло было, а ком­пи­ля­тор сам раз­бе­рёт­ся, в какой момент его применять.

В рус­ском язы­ке всё рабо­та­ет точ­но так же: есть пра­ви­ла пра­во­пи­са­ния и грам­ма­ти­ки. Нам неваж­но, в каком поряд­ке мы их изу­чи­ли, глав­ное — что­бы мы их вовре­мя при­ме­ня­ли при напи­са­нии тек­ста или в уст­ной речи. Напри­мер, мы можем сна­ча­ла прой­ти пра­ви­ло «жи-ши», а потом пра­ви­ло про «не с гла­го­ла­ми», но при­ме­нять мы их будем в том поряд­ке, какой тре­бу­ет­ся в тексте.

👉 Полу­ча­ет­ся, что смысл функ­ци­о­наль­но­го про­грам­ми­ро­ва­ния в том, что­бы опи­сать не сами чёт­кие шаги к цели, а пра­ви­ла, по кото­рым ком­пи­ля­тор сам дол­жен дой­ти до нуж­но­го результата.

Источник

5 функциональных языков программирования, которые вы должны знать

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

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

Что Такое Функциональное Программирование?

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

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

Есть сходство с философией Unix, что каждая программа должна делать одну вещь хорошо. Функция не должна касаться различных частей программы. Вместо этого она должна принимать данные на входа и давать значение на выходе.

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

Функциональное и объектно-ориентированное программирование

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

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

1. Javascript

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

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

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

2. Python

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Как и JavaScript, Python является обобщенным языком, с помощью которого можно использовать любое количество парадигм программирования. Python может иметь свои недостатки, но функциональное программирование не является одним из них. Существует даже введение в функциональное программирование в официальной документации Python.

Лямбда-выражения можно использовать несколькими способами. Один из способов использовать его в качестве стенографии для простых функций. При назначении переменной можно вызывать лямбда-выражения точно так же, как и стандартную функцию Python. Реальное преимущество лямбда-выражений заключается в использовании их в качестве анонимных функций.

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

3. Clojure

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

В отличие от JavaScript и Python, Clojure может быть не совсем знакомым языком, даже среди программистов. В случае, если вы не знакомы с Clojure – этот язык является диалектом языка программирования Lisp, который придумали к концу 1950-х годов.

Как и другие диалекты Lisp, Clojure рассматривает код как данные. Это означает, что код может эффективно изменять себя. В отличие от других диалектов Lisp, Clojure работает на платформе Java и компилируется в байт-код JVM. Это означает, что он может работать с библиотеками Java, были ли они написаны на Clojure или нет.

В отличие от предыдущих языков в этом списке, Clojure изначально является функциональным языком программирования. Это означает, что он защищает неизменность везде, где это возможно, особенно в рамках структур данных.

4. Elm

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Один из новых языков в этом списке, Elm-чисто функциональный язык, первоначально разработанный Evan Czaplicki в 2012 году. Язык приобрел популярность среди веб-разработчиков, в частности, для создания пользовательских интерфейсов.

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

Компилятор Elm предназначен для HTML, CSS и JavaScript. Так же, как вы можете использовать Clojure для написания программ, которые работают на Java, вы можете писать приложения, которые используют библиотеки JavaScript в Elm.

5. Haskell

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Haskell – это другой статически типизированный, чисто функциональный язык. В отличие от Elm, Haskell существует уже довольно долго. Первая версия языка была разработана в 1990 году. Последний стандарт-Haskell 2010, а следующая версия запланирована на 2020 год.

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

Несмотря на отсутствие популярности, Haskell был использован в некоторых широко используемых проектах. Оконный менеджер Xmonad полностью написан на языке Haskell. Pandoc, который преобразует различные типы разметки в другие форматы..

Вы новичок в программировании?

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

Источник

Современные языки программирования, которые заставят вас страдать: Часть 2, функциональные языки

Современные языки программирования, которые заставят вас страдать: Часть 2, функциональные языки

Прим. ред. Это перевод статьи Ильи Суздальницкого. Мнение редакции может не совпадать с мнением автора оригинала.

Это вторая и финальная часть перевода статьи про современные язки программирования. В первой части — «Современные языки программирования, которые заставят вас страдать: Часть 1, ООП», рассматривались объектноориентированные языки. В этой части автор подробно разбирает функциональные языки программирования которые принадлежат семейству ML ( и некоторые С-подобные).

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

Haskell

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры
Типизация: нет более мощной системы типов, чем в Haskell. Он поддерживает, как алгебраические типы данных, так и классы типов. Язык способен вывести почти любой тип.

Сложность изучения: чтобы продуктивно использовать Haskell нужно изучить теорию категорий. Даже для того, чтобы написать hello world, нужно понимать монады.

Сообщество: больше заинтересовано в академических дискуссиях, чем в решении реальных проблем.

Функциональная чистота: чистые функции — прекрасны. Побочные эффекты (взаимодействие с внешним миром, изменение состояния) причина большого количества ошибок в программах. Будучи чисто функциональным языком, Haskell полностью избавлен от них.

Конечно в языке есть обходные пути, для взаимодействия с внешним миром. Для этого используется набор инструкций (монад ввода-вывода). Это могут быть такие инструкции: получить строку с клавиатуры, использовать её в некой функции, напечатать результат в консоль. Среда выполнения делает это за нас. Мы никогда не выполняем код взаимодействующий с внешним миром напрямую.

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

Поддержка NULL: как и в Rust, Haskell не поддерживает нулевые ссылки. Вместо этого в нём есть Optional, на случай, если значения может не быть.

Обработка ошибок: некоторые функции могут выбрасывать ошибки, но более свойственный для языка подход похож на Result в Rust.

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

Сопоставление с образцом: поддерживается.

Экосистема: стандартная библиотека неорганизованна. По умолчанию, в Haskell используются функции выбрасывающие исключение, вместо возврата Option (золотой стандарт для функционального программирования). В довершение всего, у Haskell есть два менеджера пакетов — Cabal и Stack.

Вердикт: мне бы очень хотелось полюбить Haskell, однако он навсегда застрял в академических кругах. Является ли он худшим из функциональных языков? Решать вам, но я думаю, что это так.

OCaml

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Типизация: не поддерживает классы типов, но есть функторы (модули высшего порядка). Язык статически типизирован и выводит типы почти также хорошо, как Haskell.

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

Инструментарий: инструменты языка неорганизованны. Имеет три менеджера пакетов: Opam, Dune, и Esy. Язык известен некачественными сообщениями об ошибках компилятора. Это не критично, но снижает производительность программистов.

Параллелизм: разработчики годами ждут поддержки многоядерности, но её пока что не предвидится.

Поддержка NULL: нет нулевых ссылок, использует Option для неуказанных значений.

Обработка ошибок: нативный подход — использование типа Result.

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

Сопоставление с образцом: поддерживается.

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

Scala

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Экосистема: Scala — это язык из семейства Си, который выполняется на виртуальной машине Java. Это значит, что у вас есть доступ к огромной экосистеме библиотек Java.

Типизация: язык плохо справляется с приведением типов. Однако Scala поддерживает Higher-Kinded типы и типы классов.

Немногословность/читаемость: хотя программы на Scala и отличаются лаконичностью (особенно по сравнению с Java), читаемость страдает. Scala — один из немногих функциональных языков, принадлежащих к семейству Си. Си-подобные языки были предназначены для императивного программирования, а ML для функционального. Поэтому функциональный код на Scala может иногда выглядеть странно.

Синтаксис для алгебраических типов данных оставляет желать лучшего:

Этот же код на языке ReasonML:

Скорость: hello world на языке Scala может компилироваться до 10 секунд, на слабом железе. Компиляция производится только на одном ядре процессора, что отрицательно влияет на скорость.

Из-за того, что Scala работает на виртуальной машине Java, программы запускаются дольше.

Сложность изучения: один из самых сложных функциональных языков. Scala, как и C++ обладает множеством функций, которые, однако, усложняют его изучение.

Иммутабельность: Scala обладает первоклассной поддержкой неизменяемых структур данных (с использованием классов образцов).

Поддержка NULL: с одной стороны, Scala поддерживает нулевые ссылки. С другой стороны, характерный для языка способ обработки отсутствующих значений — паттерн Option.

Обработка ошибок: нативный подход — использование типа Result.

Параллелизм: можно использовать отличный инструмент — Akka.

Сопоставление с образцом: поддерживается.

Вердикт: Scala пытается делать слишком многое. Его разработчикам пришлось пойти на множество компромиссов, чтобы поддерживать как ООП, так и функциональное программирование.

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры
Сообщения об ошибках: компилятор выдаёт самые понятные сообщения об ошибках, что я когда-либо видел.

Обработка ошибок: в языке нет ошибок выполнения и исключений. Как и другие функциональные языки, использует тип Result для обработки ошибок.

Функциональная чистота: как и Haskell, Elm — чисто функциональный язык. И в данном случае это скорее минус, потому что любой рефакторинг превращается в кошмар.

Слишком строгий:

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

Скриншот с сайта https://www.reddit.com/r/ProgrammerHumor/comments/8we9zh/im_learning_elm_and_it_immediately_declared_war/

Elm настолько строгий, что использование табуляций считается синтаксической ошибкой.

Сосредоточенность на отсутствии ошибок убивает язык. В версии 0.19, взаимодействие с JS библиотеками сделали практически невозможным. Конечно для того, чтобы стимулировать людей писать свои библиотеки на Elm. Но компаний, у которых есть для этого достаточно ресурсов, крайне мало.

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

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

К сожалению, прошло уже больше года с тех пор, как была выпущена новая версия Elm (0.19.1). О состоянии разработки ничего не известно. Возможно, что она вообще больше не ведётся.

Сопоставление с образцом: поддерживается.

Иммутабельность: обладает первоклассной поддержкой неизменяемых структур данных.

Поддержка NULL: нет нулевых ссылок, использует Option для неуказанных значений.

Вердикт: Elm — отличный язык, но к сожалению у него нет будущего.

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры
Типизация: единственный минус его системы типов — отсутствие Higher-Kinded типов. Тем не менее система типов очень надежна, компилятор способен вывести практически все что угодно. F# имеет надлежащую поддержку алгебраических типов данных.

Не полностью функциональный: в отличие от Haskell/Elm, F# очень прагматичен и не обеспечивает функциональную чистоту.

Обучающие ресурсы: есть действительно хорошие учебные ресурсы.

Сложность изучения: F# — один из самых простых функциональных языков.

Экосистема: имеет довольно небольшое сообщество и в отличие от таких языков как Elixir, оно не имеет таких же замечательных библиотек.

Параллелизм: работает поверх CLR, который не имеет такой же превосходной поддержки параллелизма, как Elixir на виртуальной машине Erlang.

Поддержка NULL: NULL-значения обычно не используются. Неуказанные значения обрабатываются с помощью паттерна Option.

Обработка ошибок: ошибки обрабатываются с помощью паттерна Result.

Иммутабельность: обладает первоклассной поддержкой неизменяемых структур данных.

Сопоставление с образцом: поддерживается.

Вердикт: F# — очень надежный язык программирования с действительно хорошей системой типов. Он почти так же хорош, как Elixir для разработки Web API (подробнее об этом далее). Однако проблема F# заключается не в том, что у него есть, а в том, чего у него нет. Если сравнить его с Elixir, его функционал параллелизма, богатая экосистема и удивительное сообщество перевешивают любые преимущества статической типизации, которые предоставляет F#.

Однако F# — лучший язык для финтеха. Также язык отлично подойдёт для энтерпрайз разработки. Его мощная система типов позволяет моделировать сложную бизнес логику. Очень рекомендую прочитать эту книгу — «Domain Modeling Made Functional».

ReasonML

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры

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

Сложность изучения: ReasonML является одним из самых простых функциональных языков.

Не полностью функциональный: ReasonML очень прагматичен, ориентирован на производительность разработчиков и быстрое достижение результатов.

Типизация: его система типов почти так же хороша, как у Haskell. Самым большим недостатком является отсутствие классов типов, но он поддерживает функторы (модули высшего порядка).

ReasonML статически типизирован и выводит типы почти так же хорошо, как и Haskell.

Экосистема: как и TypeScript, ReasonML имеет доступ ко всей экосистеме JavaScript.

Взаимодействие с JavaScript/TypeScript: компилируется в обычный JavaScript. Поэтому, в одном проекте можно использовать как ReasonML, так и JavaScript/TypeScript.

ReasonML and React — отличное сочетание: поскольку ReasonML статически типизирован, нет необходимости беспокоиться о PropTypes. В отличие от JavaScript, при использовании ReasonML ничто не перерисовывается без необходимости — вы получаете отличную производительность React из коробки!

Инструменты: язык далеко не такой зрелый, как его альтернативы, так что могут возникнуть некоторые проблемы с инструментами. Например, официально рекомендуемое расширение VSCode — reason-language-server в настоящее время не работает.

ReasonML использует компилятор OCaml под капотом, а OCaml известен посредственными сообщениями об ошибках компилятора. Это не критично, но может повлиять на производительность разработчиков.

Поддержка NULL: нет нулевых ссылок, использует Option для неуказанных значений.

Иммутабельность: обладает первоклассной поддержкой неизменяемых структур данных.

Сопоставление с образцом: поддерживается.

Вердикт: это отличный язык для веб-разработки. ReasonML, вероятно, является тем, чем всегда стремился быть TypeScript, но потерпел неудачу. ReasonML добавляет статическую типизацию в JavaScript, убирая при этом все плохие фичи (и добавляя современные фичи, которые действительно нужны).

Elixir

Функциональный язык программирования примеры. Смотреть фото Функциональный язык программирования примеры. Смотреть картинку Функциональный язык программирования примеры. Картинка про Функциональный язык программирования примеры. Фото Функциональный язык программирования примеры
Экосистема: это сильная сторона языка. Автор языка также разрабатывает крутые библиотеки: Phoenix и Ecto. В отличие от других языков, у Elixir нет множества библиотек с дублирующимся функционалом, а существующие — очень хороши.

Имеет хорошую документацию, даже к стандартной библиотеке.

Фреймворк Phoenix: поддерживает из коробки: вебсокеты, routing, HTML templating language, internationalization, JSON encoders/decoders, seamless ORM integration(Ecto), sessions, SPA toolkit и многое другое. Также фреймворк известен своей производительностью — способен обрабатывать миллионы одновременных подключений на одной машине.

Фуллстек Elixir: Phoenix недавно представил LiveView, который позволяет создавать насыщенные веб-интерфейсы реального времени прямо в Elixir. LiveView даже заботится о синхронизации состояния клиента и сервера, а это значит, что нам не нужно беспокоиться о разработке и обслуживании REST/GraphQL API.

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

Такие инструменты, как Broadway, позволяют строить конвейеры приема/обработки данных в Elixir.

Типизация: на мой взгляд, отсутствие корректной статической типизации — самый большой недостаток Elixir.

Скорость: компилятор Elixir является многопоточным и обеспечивает невероятно высокую скорость компиляции. В отличие от JVM, виртуальная машина Erlang запускается быстро. Производительность во время выполнения очень хороша.

Надёжность: код на Elixir выполняется поверх Erlang, который использовался более 30 лет для создания самого надежного программного обеспечения в мире. Некоторые программы, работающие на виртуальной машине Erlang, смогли достичь надежности 99,9999999%. Ни одна другая платформа в мире не может похвастаться таким же уровнем надежности.

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

Elixir, в отличие от Go, убивает только тот процесс в котором произошла ошибка, а не всю программу. Более того, этот процесс будет автоматически перезапущен его супервизором.

Elixir строится на основе Erlang, который известен своими большими возможностями распараллеливания, и использует совершенно другой подход к параллелизму, называемый моделью актора. В рамках этой модели, между процессами (акторами) нет ничего общего. Каждый процесс поддерживает свое собственное внутреннее состояние, и единственный способ общения между различными процессами — отправка сообщений.

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

Масштабирование: параллельные вычисления в Go быстрее чем в Elixir, если это происходит на одной машине. Но при масштабировании происходит обратное. Elixir легко справляется с такими вещами как: кластеризация, RPC и сетевые взаимодействия. В некотором смысле, виртуальная машина Erlang работала с микросервисами за десятилетия до того, как они вошли в обиход. Каждый процесс можно рассматривать как микросервис — как и микросервисы, процессы независимы друг от друга. Микросервисы без сложностей Kubernetes? Именно для этого и был создан Elixir.

Обработка ошибок: язык использует уникальный подход к обработке ошибок. В то время как чисто функциональные языки (Haskell/Elm) предназначены для минимизации вероятности появления ошибок, Elixir предполагает, что ошибки неизбежно произойдут.

Выбрасывать исключения в Elixir — правильно, в то время как обрабатывать исключения обычно не рекомендуется. Вместо этого супервизор процесса автоматически перезапустит неудачный процесс, чтобы программа продолжила работать.

Сложность изучения: язык можно освоить за пару месяцев. Однако освоение OTP может занять некоторое время. OTP — киллер фича языка. OTP — это набор инструментов и библиотек от Erlang, на которых строится Elixir. Это секретный ингредиент, который значительно упрощает построение параллельных и распределенных программ.

Обучающие ресурсы: их существует огромное количество. И почти все из них подойдут для новичков.

Сопоставление с образцом: поддерживается.

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

Вердикт: Elixir, вероятно, является самым зрелым из всех функциональных языков. Он работает на виртуальной машине, созданной для функционального программирования. Язык был разработан с нуля для параллельных вычислений, и идеально подходит для современной эры многоядерных процессоров. Это лучший язык для Web API. OTP и модель акторов делают язык лучшим решением для параллельных и распределённых программ.

Подходящий инструмент

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

Go — лучший язык для системного программирования. Для фронтенда несомненно стоит выбрать ReasonML. Абсолютный лидер для разработки Web API — Elixir. Как и для любых задач связанных с параллельными и распределёнными программами. Python, это к сожалению единственный адекватный вариант для data science.

Это довольно неоднозначная статья. Очевидно, что автор предпочитает функциональные языки программирования объектноориентированным. Если вы не согласны с рейтингом и можете аргументировать свою точку зрения, добро пожаловать в комментарии.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *