Information
- Rating
- 1,064-th
- Location
- Санкт-Петербург, Санкт-Петербург и область, Россия
- Date of birth
- Registered
- Activity
Specialization
Фулстек разработчик
Ведущий
JavaScript
HTML
CSS
React
Scala
TypeScript
Vite
Адаптивная верстка
Кроссбраузерная верстка
Next.js
Я отразил своё мнение по этому поводу в статье, предметно, с примерами кода как на Scala так и на JS. То, что лично вас это не убеждает полностью ортогонально правдивости или ложности моей аргументации.
Вы не отвечаете на мой вопрос: я не спрашивал вас о вашем карьерном пути в Erlang'e, я спрашивал: "как часто вы видите применение паттернов ФП (и, если вам угодно, "программирование в функциональном стиле") в проектах написанных на JavaScript?" В ответ на это вы приводите мне Erlang в качестве примера с аргументацией "там ничего из того, что вы перечислили - нет". И что это доказывает? Я вообще не могу понять, к чему вы это написали: естественно Эрланг функциональный язык, да, в нём отсутствуют из коробки некоторые перечисленные мною фичи, а еще там нет переменных, циклов и есть иммутабельность (и это, в том числе те признаки, что я указал в статье). Я нигде не писал, что в ФЯП должны присутствовать все пункты одновременно, более того: речь вообще шла исключительно о JS/TS. Вы упомянули, что в статье ничего не сказано про HOF. В ней ничего нет об этом потому, что в JS HOF есть, проблема в том, что на практике это никак не помогает, т.к. язык и его экосистема сподвигает вас писать циклы, сподвигает вас писать мутабельный код, сподвигает вас использовать что угодно кроме тайпклассов, сподвигает вас писать try/catch c мутациями внутри, сподвигает писать кругом проверки на null & undefined, и так далее, и всё это потому, что в этом языке так писать удобнее, эргономичнее и проще, а еще именно такие инструменты у вас имеются из коробки, а код в большинстве случаев хоть и менее безопасный но более читабельный и привычный для комьюнити и разработчиков. Да, в Эрланг у вас может не быть HKT, но и цикл вы не напишите.
Я нигде и не утверждал обратного, вы за меня додумываете. Если бы у вас был опыт написания строготипизированного кода в функциональном стиле на TS, то вы бы знали, какой эквилибристикой порой приходится заниматься, чтобы ваши типы "сошлись" и чтобы TS вас верно понял. Особенно когда речь касается типизации функций высшего порядка. Откройте source fp-ts и посмотрите, как они определяют функцию pipe, например.
С такого. У вас нарушается принцип "подстановки" (substitution) и это ломает композицию. Как минимум, вы получаете строгую зависимость от порядка вычислений.
Пока что из всей дискуссии я так и не понял, что конкретно делает Erlang "недосягаемым ФЯП" в рамках вашего определения через HOF в системе типов. А в местах, где должен идти аргумент вы просто вставляете ":-)". Не говоря о том, что часть вашего текста - это ваше оценочные суждения поданные в императивной и назидательной нотации без какого-либо раскрытия и доказательства. Вы либо приводите аргумент полностью, от и до, без намёков и пространных суждений, либо не приводите его вовсе, а то мне приходится заниматься дешифровкой ваших сообщений.
Да, вчера уже была обнаружена эта ошибка, меня поглотила тьма, когда я это писал. Этот кусок удален, текст скорректирован!
Спасибо вам огромное, что заметили эту жесть)) Писал этот кусок глубокой ночью, то ли в каких-то более старых версиях ТS была эта проблема (но даже если и была, то выглядела совсем не так, как я ее описал), то ли я ее сам "выдумал". Весь этот кусок удалил, ваше замечание полностью по делу, спасибо еще раз!
На мой взгляд вы очень сильно упрощаете. И ваша последняя строчка, где вы как бы "забираете" часть своего аргумента назад - прямое тому подтверждение. JS даже не рядом со Scala в вопросах "функциональности", ни на каком из уровней. Плотность и эргономика функциональных фич в Scala на порядки выше, а систему типов и сравнивать смешно.
Вы либо передёргиваете, либо мы изначально говорим о разном. Если вы говорите про спецификацию типов, тогда в вашем первом посту я неверно вас понял.
В узком смысле слова вы правы: СП - это свойство выражения, а не языка. Но проблема в том, что то, что не ссылочно-прозрачно крайне плохо композируется. Если нет функциональной композции и / или она ограниченна, то писать функциональный код становится проблематично и больно.
Можно долго спорить о терминологии, но факт в том, что культура написания кода на разных языках формируется не только на основании спецификаций и систем типов, но еще и в практическо-прагматической среде. Приживается то, что более естественно для конкретного языка, что более удобно для решения задач, под которые этот язык подходит. И на мой взгляд это куда важнее, чем то, о чём вы говорите выше. Я к тому, что ставить == между языками с точки зрения "функциональности" основываясь только на том, что система типов знает про HOF - это очень сильное упрощение, которое полностью оторванно от реальной практики применения языков: сколько вы лично видели проектов в продакшене на JS, где активно используется карирование, частичное применение, монады, изоляция эффектов(то, что для вас всё это не является критерием фп - и я хочу это подчеркнуть двумя толстыми линиями - это ваше личное оценочное суждение а не научный консенсус)? В то же время чисто функциональную Scala я вижу регулярно, в особенности после роста популярности Cats Effect и Zio
удалено
Я очень со многим из того, что вы пишите согласен.
В одной из книг про Cats Effect читал такое определение:
Вспомнил его, когда читал ваш пост, показалось довольно созвучным.
Согласен, но с одним на мой взгляд важным уточнением: в Scala последние несколько лет укоренилась тенденция создания эффектных систем (Cats Effect, Zio), что очень сильно "качнуло" маятник в сторону чистого функционального программирования.Т.е. да, в языке действительно ярко выраженная мультипарадигмальность, но на практике эта дихотомия сегодня ощутимо менее выражена, если сравнивать с периодом популярности Akka, например.
Вот это, и то, что вы пишите касательно Haskell-like языков - довольно интересный тейк в том смысле, что ведь действительно в мире программирования есть такие... "Маппинги" вроде "Мы говорим ООП, подразумеваем - Java", мы говорим "FP, подразумеваем - Haskell", но довольно серьезный вопрос в том, насколько корректны подобные "маппинги" в принципе.
Я утверждал обратное — что мутабельность по умолчанию ссылочную прозрачность нарушает, а не что иммутабельность её гарантирует, это разные тезисы.
Про конфликт TCO и ленивости — не очень понял тезис. Haskell ленивый, но TCO там есть и используется. Проблема стека трансформируется в space leaks, но не исчезает совсем. Если имеется в виду что они решают разные проблемы — согласен, но это скорее ортогональность, чем конфликт.
Касательно try/catch и Erlang: конкретно тут он ни при чём, в том блоке я разбирал try/catch в JS, и там это является инструкцией, а не выражением. И это не моё мнение, а факт.
Интересное определение, но оно ломается на примере, который вы сами привели — Erlang динамически типизирован, никакой системы типов с HOF там нет. Тем не менее функциональным языком он считается.
Если вы имели в виду просто сам факт того, что для ФП необходимо иметь возможность писать HOF - то с этим глупо спорить, всё так. Моя проблема с формулировкой в том, что Если HOF — единственный(или основной) критерий, то JS функциональный язык, it's simple as that.
Звучит как ваше оценочное суждение без каких-либо оснований.
Я не утверждал, что функтор - это HKT. Я пытался на простом примере показать механизм системы типов, который позволяет выразить тайпкласс (т. е. что функтор параметризован HKT)
Этот тезис «кочует» по страницам книг, звучит в публичных выступлениях, есть даже целые курсы, в т.ч. от крупных и известных платформ вроде «frontend masters» где это мнение присутствует, так же я сослался на свой личный опыт проведения интервью. Я к тому, что у нас с вами опыт может сильно отличаться и это вполне нормально. В то же время то, что вы не слышали тезис «JS - функциональный язык» не означает, что этого тезиса не существует.
Всё это - ваше личное оценочное суждение, не более. Никакого снобизма тут не было: я лишь констатировал факт того, что «из коробки» в языке решений не существует, требуется использование дополнительных инструментов. Некоторые из них абсолютно гениальные(effect ts, fp-ts), некоторые, на мой взгляд, менее удачные.
Effect-ts в продакшене попробовать не довелось, а вот с fp-ts поработал на двух проектах.
На мой взгляд, библиотека очень мощная, но с онбордингом возникали определенные сложности. Если люди прежде не писали на функциональных языках, код на fp-ts для них выглядит тяжеловесно. И местами, надо признать, это ощущение вполне заслуженно — порог входа высокий и код визуально кажется совсем "чужим", не похожим на привычный TS.
Кроме того, есть сугубо практический нюанс интеграции. Допустим, мы пишем React-приложение. Подключаем React Query, которая, естественно, ничего не знает про монады Task / TaskEither. Приходится писать адаптеры, превращающие ТЕ обратно в обычные Promise. Да, это пара строк кода, но React Query — не единственная такая библиотека. Любой хук форм или роутер заставляет держать в голове эти пограничные прослойки.
В итоге появляется постоянный оверхед (пусть и небольшой), оправданность которого в команде — вопрос дискуссионный. Лично я считал, что строгость типов и обработка ошибок того стоят, кто-то другой скажет, что нет. Собственно, это прямое продолжение того, что я в статье назвал «гравитацией языка» — экосистема постоянно тянет тебя обратно в императивный мир.
По Haskell абсолютно справедливое замечание, стоило быть точнее. С одним лишь важным нюансом: насколько я знаю, Haskell "культурно поощряет" именно стиль с использованием Either / Maybe монад.
По ОCaml и HKT - супер важное уточнение. В таком случае отсутствие HKT - это больше ограничение выразительности при написании обобщённых абстракций, а не маркер "функциональности" языка как таковой. Поправлю формулировку, спасибо!
Да, это рабочий паттерн и важное уточнение, спасибо — мне стоило про это упомянуть. Но то, что я сам про это забыл, лишний раз доказывает тезис: язык мне здесь не помогает, это просто соглашение, которое нужно держать в голове и применять в каждом switch вручную.
Ну и проблему открытой иерархии это, к сожалению, не решает.